From 9fed188672f7012174a33000a2df8833756f214a Mon Sep 17 00:00:00 2001 From: r00bbert <280805750+r00bbert@users.noreply.github.com> Date: Sun, 17 May 2026 14:13:01 +0200 Subject: [PATCH 01/18] Phase 1: rename plugin metadata and main file - Rename opentrust.php to open-trust-center-by-ettic.php - Plugin Name: OpenTrust to Open Trust Center by Ettic - Plugin URI: /opentrust to /open-trust-center-by-ettic - Text Domain: opentrust to open-trust-center-by-ettic - Version: 1.1.1 to 1.2.0 - readme.txt H1 and Stable tag updated Trademark rename per wp.org review. Folder stays opentrust/ during dev; renamed at submission build. --- opentrust.php => open-trust-center-by-ettic.php | 10 +++++----- readme.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) rename opentrust.php => open-trust-center-by-ettic.php (95%) diff --git a/opentrust.php b/open-trust-center-by-ettic.php similarity index 95% rename from opentrust.php rename to open-trust-center-by-ettic.php index d8d7d03..0f8a8a5 100644 --- a/opentrust.php +++ b/open-trust-center-by-ettic.php @@ -1,16 +1,16 @@ Date: Sun, 17 May 2026 14:15:48 +0200 Subject: [PATCH 02/18] Phase 2: tear down v1-v5 migration chain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop maybe_upgrade() and its init hook, plus the five migration helpers (rename_cpt_slugs_v4, rename_postmeta_keys_v5, backfill_uuids, backfill_model_snapshot). ~180 LOC removed. Reset OPENTRUST_DB_VERSION constant to 1 (fresh-release baseline). Drop legacy ot_* slugs from uninstall.php (their migration path is gone). Keep OpenTrust_CPT::LEGACY_META_MAP intact — still needed by the importer's back-compat remap. Treating 1.2.0 as the first version intended for distribution. Any developer running an older opentrust install migrates via export/import, not in-place schema bumps. --- includes/class-opentrust-cpt.php | 12 +- includes/class-opentrust.php | 181 ------------------------------- open-trust-center-by-ettic.php | 8 +- uninstall.php | 12 -- 4 files changed, 7 insertions(+), 206 deletions(-) diff --git a/includes/class-opentrust-cpt.php b/includes/class-opentrust-cpt.php index 4bc5181..89622d3 100644 --- a/includes/class-opentrust-cpt.php +++ b/includes/class-opentrust-cpt.php @@ -47,14 +47,10 @@ final class OpenTrust_CPT { /** * Legacy postmeta keys from v1.0–v1.1, mapped old `_ot_*` → new - * `_opentrust_*`. The 2-character `_ot_` prefix collided too easily in the - * shared wp_postmeta table; v5 of the schema renames every plugin-owned - * key. Single source of truth for the v4→v5 migration - * (OpenTrust::rename_postmeta_keys_v5()), the import back-compat remap - * (OpenTrust_IO::remap_legacy_meta_keys()), and uninstall cleanup. - * - * @deprecated 1.1.1 Drop in 2.0.0 once v1.x upgrades are no longer - * supported, alongside the `if ($current < 5)` migration branch. + * `_opentrust_*`. Retained for import back-compat: legacy archives + * (exported by v1.0.x/v1.1.x) still carry these keys, and the importer + * remaps them on read via OpenTrust_IO::remap_legacy_meta_keys(). + * Phase 8 extends the chain through `_ettic_otc_*`. */ public const LEGACY_META_MAP = [ // Shared identity. diff --git a/includes/class-opentrust.php b/includes/class-opentrust.php index 25cca3a..9a804c5 100644 --- a/includes/class-opentrust.php +++ b/includes/class-opentrust.php @@ -33,9 +33,6 @@ private function __construct() { // Flush rewrite rules when settings change (transient flag). add_action('init', [$this, 'maybe_flush_rewrites'], 99); - // Check for DB schema upgrades. - add_action('init', [$this, 'maybe_upgrade'], 5); - // Bump the render-cache version on any OpenTrust CPT change. Catches // saves, deletes, trash/untrash, and publish transitions in one wire-up. OpenTrust_CPT::register_invalidator(OpenTrust_CPT::ALL, [$this, 'invalidate_cache']); @@ -170,184 +167,6 @@ public function register_query_vars(array $vars): array { return $vars; } - /** - * Schema upgrade hook. Runs on every init at priority 5. Future schema - * migrations land here, gated on the current value of opentrust_db_version - * vs. the OPENTRUST_DB_VERSION constant. opentrust_db_version is only - * advanced once, at the tail — so an interrupted migration retries cleanly - * on the next init, and every migration step must be idempotent. - */ - public function maybe_upgrade(): void { - $current = (int) get_option('opentrust_db_version', 0); - if ($current === (int) OPENTRUST_DB_VERSION) { - return; - } - - // v3 → v4: rename CPT slugs from `ot_*` to `opentr_*` to satisfy the - // wp.org 4-character-prefix rule. Runs first so any v1→v4 jump renames - // the rows before the v1→v2 UUID back-fill queries them — the back-fill - // resolves OpenTrust_CPT::ALL to the new slugs, so the rows must already - // carry those slugs by the time it runs. Runs at init priority 5, - // before OpenTrust_CPT::register_post_types() at priority 10. - if ($current < 4) { - self::rename_cpt_slugs_v4(); - } - - // v4 → v5: rename postmeta keys from `_ot_*` to `_opentrust_*` so the - // plugin no longer uses a 2-character prefix in the shared postmeta - // table. MUST run before the v1→v2 UUID back-fill below: the back-fill - // stamps `_opentrust_uuid` on any post that lacks it, so a v1 post's - // legacy `_ot_uuid` row has to be renamed to `_opentrust_uuid` first — - // otherwise the back-fill would see no `_opentrust_uuid`, add a second - // one, and the post would end up with two conflicting UUID rows. - if ($current < 5) { - self::rename_postmeta_keys_v5(); - } - - // v1 → v2: back-fill _opentrust_uuid on existing CPT posts. Runs after - // the v4→v5 rename above so it never double-stamps a post that already - // carries a (renamed) legacy UUID. - if ($current < 2) { - self::backfill_uuids(); - } - - // v2 → v3: register the daily AI-model-refresh cron and back-fill - // the active-model snapshot so existing installs don't render a raw - // id before the first cron tick. - if ($current < 3) { - OpenTrust_Admin_AI::schedule_cron(); - self::backfill_model_snapshot(); - } - - update_option('opentrust_db_version', OPENTRUST_DB_VERSION, false); - set_transient('opentrust_flush_rewrite', true); - $this->invalidate_cache(); - - // The chat corpus transient is locale-keyed and not bound to - // opentrust_cache_version, so invalidate_cache() above doesn't bust - // it. After the v4 rename the surviving corpus would be valid but - // mention the old slug context in admin telemetry — drop it so the - // next chat request rebuilds against the renamed rows. - if (class_exists('OpenTrust_Chat_Corpus')) { - OpenTrust_Chat_Corpus::invalidate(); - } - } - - /** - * Seed the active-model snapshot from the existing per-provider transient - * cache. No HTTP — runs at upgrade time only. - */ - private static function backfill_model_snapshot(): void { - $settings = self::get_settings(); - $snap = OpenTrust_Admin_AI::instance()->snapshot_for_provider( - (string) ($settings['ai_provider'] ?? ''), - (string) ($settings['ai_model'] ?? '') - ); - if ($snap === null) { - return; - } - $settings['ai_model_display_name'] = $snap['display_name']; - $settings['ai_model_recommended'] = $snap['recommended']; - OpenTrust_Admin_Settings::instance()->save_settings_raw($settings); - } - - /** - * Rewrite wp_posts.post_type for each renamed CPT. Idempotent: if the - * migration is interrupted, opentrust_db_version stays unadvanced and the - * next init retries. Revisions carry post_type='revision' and are not - * matched. Translation linkage (WPML/Polylang) is keyed by post ID, not - * by slug, so existing translations stay paired. - * - * Collects affected IDs before the UPDATE so each row's WP_Post entry in - * the object cache can be invalidated — otherwise post_type checks that - * read from cache return stale 'ot_*' values until the cache expires. - * - * @deprecated 1.1.0 Drop in 2.0.0 once v1.0.x upgrades are no longer - * supported. Also remove the `if ($current < 4)` branch in - * maybe_upgrade() and the OpenTrust_CPT::LEGACY_* constants. - */ - private static function rename_cpt_slugs_v4(): void { - global $wpdb; - foreach (OpenTrust_CPT::LEGACY_MAP as $old => $new) { - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- One-shot schema migration; per-row clean_post_cache() runs below + opentrust_cache_version bumped after maybe_upgrade. - $ids = $wpdb->get_col( - $wpdb->prepare("SELECT ID FROM {$wpdb->posts} WHERE post_type = %s", $old) - ); - if (empty($ids)) { - continue; - } - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- One-shot schema migration; per-row clean_post_cache() runs below + opentrust_cache_version bumped after maybe_upgrade. - $wpdb->update( - $wpdb->posts, - ['post_type' => $new], - ['post_type' => $old], - ['%s'], - ['%s'] - ); - foreach ($ids as $id) { - clean_post_cache((int) $id); - } - } - } - - /** - * Rewrite wp_postmeta.meta_key for every plugin-owned postmeta key, from - * the legacy `_ot_*` prefix to `_opentrust_*`. Idempotent: a bulk UPDATE - * keyed on the old meta_key matches nothing on a re-run, and - * opentrust_db_version stays unadvanced until the tail of maybe_upgrade() - * so an interrupted migration retries cleanly. - * - * The UPDATE is keyed on meta_key alone, so it catches postmeta on posts, - * revisions, and attachments alike. Affected post IDs are collected first - * so each WP_Post's meta cache can be invalidated — otherwise get_post_meta - * would serve stale `_ot_*` lookups until the cache expires. - * - * @deprecated 1.1.1 Drop in 2.0.0 once v1.0.x upgrades are no longer - * supported. Also remove the `if ($current < 5)` branch in - * maybe_upgrade() and OpenTrust_CPT::LEGACY_META_MAP. - */ - private static function rename_postmeta_keys_v5(): void { - global $wpdb; - foreach (OpenTrust_CPT::LEGACY_META_MAP as $old => $new) { - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- One-shot schema migration; per-row clean_post_cache() runs below + opentrust_cache_version bumped after maybe_upgrade. - $ids = $wpdb->get_col( - $wpdb->prepare("SELECT DISTINCT post_id FROM {$wpdb->postmeta} WHERE meta_key = %s", $old) - ); - if (empty($ids)) { - continue; - } - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- One-shot schema migration; per-row clean_post_cache() runs below + opentrust_cache_version bumped after maybe_upgrade. - $wpdb->update( - $wpdb->postmeta, - ['meta_key' => $new], - ['meta_key' => $old], - ['%s'], - ['%s'] - ); - foreach ($ids as $id) { - clean_post_cache((int) $id); - } - } - } - - private static function backfill_uuids(): void { - $posts = get_posts([ - 'post_type' => OpenTrust_CPT::ALL, - 'post_status' => 'any', - 'posts_per_page' => -1, - 'fields' => 'ids', - 'meta_query' => [ - [ - 'key' => '_opentrust_uuid', - 'compare' => 'NOT EXISTS', - ], - ], - ]); - foreach ($posts as $post_id) { - update_post_meta((int) $post_id, '_opentrust_uuid', wp_generate_uuid4()); - } - } - public function maybe_flush_rewrites(): void { if (get_transient('opentrust_flush_rewrite')) { delete_transient('opentrust_flush_rewrite'); diff --git a/open-trust-center-by-ettic.php b/open-trust-center-by-ettic.php index 0f8a8a5..6500d5c 100644 --- a/open-trust-center-by-ettic.php +++ b/open-trust-center-by-ettic.php @@ -22,7 +22,7 @@ define('OPENTRUST_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('OPENTRUST_PLUGIN_URL', plugin_dir_url(__FILE__)); define('OPENTRUST_PLUGIN_FILE', __FILE__); -define('OPENTRUST_DB_VERSION', 5); +define('OPENTRUST_DB_VERSION', 1); require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust.php'; require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-admin.php'; @@ -70,10 +70,8 @@ // Custom tables. OpenTrust_Chat_Log::create_table(); - // Stamp the schema version on a true first install only. On reactivation - // after an in-place upgrade (deactivate → upload zip → activate) the - // option already exists with the prior version; leaving it untouched lets - // OpenTrust::maybe_upgrade() walk pending migrations on the next init. + // Stamp the schema version on a true first install only. Future schema + // changes (none today) would bump this constant and re-check here. if (false === get_option('opentrust_db_version', false)) { update_option('opentrust_db_version', OPENTRUST_DB_VERSION, false); } diff --git a/uninstall.php b/uninstall.php index 121db72..c8a1f06 100644 --- a/uninstall.php +++ b/uninstall.php @@ -20,24 +20,12 @@ // loading the rest of the plugin, so we cannot reference OpenTrust_CPT::ALL // here. The list below MUST stay in sync with that constant; if a CPT is // added or renamed there, mirror the change here. -// -// Legacy ot_* slugs included as a belt-and-suspenders cleanup for the corner -// case of a v1.0.x install uninstalling before the v3→v4 migration in -// OpenTrust::maybe_upgrade() has had a chance to run. -// -// @deprecated 1.1.0 Drop the ot_* entries in 2.0.0 once v1.0.x upgrades are no -// longer supported. $ot_post_types = [ 'opentr_policy', 'opentr_subprocessor', 'opentr_certification', 'opentr_data_practice', 'opentr_faq', - 'ot_policy', - 'ot_subprocessor', - 'ot_certification', - 'ot_data_practice', - 'ot_faq', ]; foreach ($ot_post_types as $ot_post_type) { From 09e5e689a63468a27fbbd3b800c7f57166ae15d9 Mon Sep 17 00:00:00 2001 From: r00bbert <280805750+r00bbert@users.noreply.github.com> Date: Sun, 17 May 2026 14:21:08 +0200 Subject: [PATCH 03/18] Phase 3: rename PHP class/constant identifiers to ettic_otc Bulk rename across all PHP source: - OpenTrust class to Ettic_OTC (main class) - OpenTrust_* classes to Ettic_OTC_* (25 classes, 420 refs) - OPENTRUST_* constants to ETTIC_OTC_* (5 constants) - class-opentrust-*.php to class-ettic-otc-*.php (25 files) - [OpenTrust] debug-log prefix to [ettic-otc] - .phpstan-bootstrap.php updated to match - 5 user-facing brand strings preserved as Open Trust Center Storage identifiers (option keys, postmeta, CPTs, hooks) keep old names for Phase 4. Text domain unchanged for Phase 6. --- .phpstan-bootstrap.php | 20 ++--- ...in-ai.php => class-ettic-otc-admin-ai.php} | 80 +++++++++--------- ...hp => class-ettic-otc-admin-questions.php} | 24 +++--- ...w.php => class-ettic-otc-admin-review.php} | 14 ++-- ...php => class-ettic-otc-admin-settings.php} | 70 ++++++++-------- ...ls.php => class-ettic-otc-admin-tools.php} | 46 +++++----- ...st-admin.php => class-ettic-otc-admin.php} | 58 ++++++------- ...atalog.php => class-ettic-otc-catalog.php} | 14 ++-- ...et.php => class-ettic-otc-chat-budget.php} | 10 +-- ...us.php => class-ettic-otc-chat-corpus.php} | 34 ++++---- ...t-log.php => class-ettic-otc-chat-log.php} | 10 +-- ...ch.php => class-ettic-otc-chat-search.php} | 2 +- ...s.php => class-ettic-otc-chat-secrets.php} | 2 +- ...class-ettic-otc-chat-stream-collector.php} | 14 ++-- ...hp => class-ettic-otc-chat-summarizer.php} | 28 +++---- ...rust-chat.php => class-ettic-otc-chat.php} | 82 +++++++++--------- ...ntrust-cpt.php => class-ettic-otc-cpt.php} | 22 ++--- ...pentrust-io.php => class-ettic-otc-io.php} | 60 ++++++------- ...-render.php => class-ettic-otc-render.php} | 72 ++++++++-------- ...ory.php => class-ettic-otc-repository.php} | 20 ++--- ...ersion.php => class-ettic-otc-version.php} | 8 +- ...lass-opentrust.php => class-ettic-otc.php} | 32 +++---- includes/data/data-practice-catalog.php | 2 +- ...ass-ettic-otc-chat-provider-anthropic.php} | 4 +- ... class-ettic-otc-chat-provider-openai.php} | 8 +- ...ss-ettic-otc-chat-provider-openrouter.php} | 6 +- ....php => class-ettic-otc-chat-provider.php} | 18 ++-- open-trust-center-by-ettic.php | 84 +++++++++---------- templates/chat.php | 12 +-- templates/partials/certifications.php | 6 +- templates/partials/data-practices.php | 4 +- templates/partials/policies.php | 4 +- templates/partials/policy-single.php | 2 +- templates/partials/subprocessors.php | 2 +- templates/trust-center.php | 32 +++---- uninstall.php | 12 +-- 36 files changed, 459 insertions(+), 459 deletions(-) rename includes/{class-opentrust-admin-ai.php => class-ettic-otc-admin-ai.php} (94%) rename includes/{class-opentrust-admin-questions.php => class-ettic-otc-admin-questions.php} (96%) rename includes/{class-opentrust-admin-review.php => class-ettic-otc-admin-review.php} (95%) rename includes/{class-opentrust-admin-settings.php => class-ettic-otc-admin-settings.php} (94%) rename includes/{class-opentrust-admin-tools.php => class-ettic-otc-admin-tools.php} (94%) rename includes/{class-opentrust-admin.php => class-ettic-otc-admin.php} (85%) rename includes/{class-opentrust-catalog.php => class-ettic-otc-catalog.php} (96%) rename includes/{class-opentrust-chat-budget.php => class-ettic-otc-chat-budget.php} (98%) rename includes/{class-opentrust-chat-corpus.php => class-ettic-otc-chat-corpus.php} (96%) rename includes/{class-opentrust-chat-log.php => class-ettic-otc-chat-log.php} (97%) rename includes/{class-opentrust-chat-search.php => class-ettic-otc-chat-search.php} (99%) rename includes/{class-opentrust-chat-secrets.php => class-ettic-otc-chat-secrets.php} (99%) rename includes/{class-opentrust-chat-stream-collector.php => class-ettic-otc-chat-stream-collector.php} (93%) rename includes/{class-opentrust-chat-summarizer.php => class-ettic-otc-chat-summarizer.php} (93%) rename includes/{class-opentrust-chat.php => class-ettic-otc-chat.php} (94%) rename includes/{class-opentrust-cpt.php => class-ettic-otc-cpt.php} (99%) rename includes/{class-opentrust-io.php => class-ettic-otc-io.php} (94%) rename includes/{class-opentrust-render.php => class-ettic-otc-render.php} (91%) rename includes/{class-opentrust-repository.php => class-ettic-otc-repository.php} (95%) rename includes/{class-opentrust-version.php => class-ettic-otc-version.php} (97%) rename includes/{class-opentrust.php => class-ettic-otc.php} (93%) rename includes/providers/{class-opentrust-chat-provider-anthropic.php => class-ettic-otc-chat-provider-anthropic.php} (99%) rename includes/providers/{class-opentrust-chat-provider-openai.php => class-ettic-otc-chat-provider-openai.php} (98%) rename includes/providers/{class-opentrust-chat-provider-openrouter.php => class-ettic-otc-chat-provider-openrouter.php} (93%) rename includes/providers/{class-opentrust-chat-provider.php => class-ettic-otc-chat-provider.php} (98%) diff --git a/.phpstan-bootstrap.php b/.phpstan-bootstrap.php index c97c929..5672642 100644 --- a/.phpstan-bootstrap.php +++ b/.phpstan-bootstrap.php @@ -7,18 +7,18 @@ declare(strict_types=1); -if (!defined('OPENTRUST_VERSION')) { - define('OPENTRUST_VERSION', '1.0.0'); +if (!defined('ETTIC_OTC_VERSION')) { + define('ETTIC_OTC_VERSION', '1.0.0'); } -if (!defined('OPENTRUST_PLUGIN_DIR')) { - define('OPENTRUST_PLUGIN_DIR', __DIR__ . '/'); +if (!defined('ETTIC_OTC_PLUGIN_DIR')) { + define('ETTIC_OTC_PLUGIN_DIR', __DIR__ . '/'); } -if (!defined('OPENTRUST_PLUGIN_URL')) { - define('OPENTRUST_PLUGIN_URL', 'https://example.com/wp-content/plugins/opentrust/'); +if (!defined('ETTIC_OTC_PLUGIN_URL')) { + define('ETTIC_OTC_PLUGIN_URL', 'https://example.com/wp-content/plugins/open-trust-center-by-ettic/'); } -if (!defined('OPENTRUST_PLUGIN_FILE')) { - define('OPENTRUST_PLUGIN_FILE', __DIR__ . '/opentrust.php'); +if (!defined('ETTIC_OTC_PLUGIN_FILE')) { + define('ETTIC_OTC_PLUGIN_FILE', __DIR__ . '/open-trust-center-by-ettic.php'); } -if (!defined('OPENTRUST_DB_VERSION')) { - define('OPENTRUST_DB_VERSION', 2); +if (!defined('ETTIC_OTC_DB_VERSION')) { + define('ETTIC_OTC_DB_VERSION', 1); } diff --git a/includes/class-opentrust-admin-ai.php b/includes/class-ettic-otc-admin-ai.php similarity index 94% rename from includes/class-opentrust-admin-ai.php rename to includes/class-ettic-otc-admin-ai.php index 9c49c46..b33c718 100644 --- a/includes/class-opentrust-admin-ai.php +++ b/includes/class-ettic-otc-admin-ai.php @@ -2,21 +2,21 @@ /** * AI Chat settings tab and its admin-post handlers. * - * Owns the entire "AI Chat" surface inside the OpenTrust settings page: + * Owns the entire "AI Chat" surface inside the Ettic_OTC settings page: * the provider picker (Anthropic primary, others behind an "advanced" * disclosure), the per-provider key card with validate-and-save flow, * the post-key model picker + budget/limit form, and the four * admin-post.php endpoints that drive key save/forget/refresh and the * summary-backfill sweep. * - * Bootstrapped by OpenTrust_Admin's constructor; subscribes its own + * Bootstrapped by Ettic_OTC_Admin's constructor; subscribes its own * admin_post_* hooks. The settings page (which still lives on - * OpenTrust_Admin as the menu callback) calls render_ai_tab() when the + * Ettic_OTC_Admin as the menu callback) calls render_ai_tab() when the * "ai" tab is active. * * Settings writes that bypass the sanitize_settings filter (key * validation flips ai_enabled / ai_provider / ai_model_list_cached_at) - * route through OpenTrust_Admin_Settings::save_settings_raw(). + * route through Ettic_OTC_Admin_Settings::save_settings_raw(). */ declare(strict_types=1); @@ -25,7 +25,7 @@ exit; } -final class OpenTrust_Admin_AI { +final class Ettic_OTC_Admin_AI { public const CRON_HOOK = 'opentrust_ai_models_refresh'; public const CACHE_TTL = 25 * HOUR_IN_SECONDS; // Slightly > daily cron cadence so the cache never expires between ticks. @@ -53,7 +53,7 @@ private function __construct() { // ────────────────────────────────────────────── public function render_ai_tab(array $settings): void { - $stored_keys = OpenTrust_Chat_Secrets::get_all(); + $stored_keys = Ettic_OTC_Chat_Secrets::get_all(); $active_provider = $settings['ai_provider'] ?? ''; $has_active_key = $active_provider !== '' && isset($stored_keys[$active_provider]); $is_non_anthropic_active = $has_active_key && $active_provider !== 'anthropic'; @@ -91,7 +91,7 @@ public function render_ai_tab(array $settings): void {

Anthropic Claude with the native Citations API to answer visitor questions about your trust center. Every claim the assistant makes is tied to an exact quote from one of your published documents — so no policy text is invented and nothing is paraphrased into something you did not actually publish.', 'opentrust'), + __('Ettic_OTC uses Anthropic Claude with the native Citations API to answer visitor questions about your trust center. Every claim the assistant makes is tied to an exact quote from one of your published documents — so no policy text is invented and nothing is paraphrased into something you did not actually publish.', 'opentrust'), ['strong' => []] ); ?> @@ -141,10 +141,10 @@ public function render_ai_tab(array $settings): void { * up-to-date summary. */ private function render_summary_backfill_banner(array $settings, bool $has_active_key): void { - if (!$has_active_key || empty($settings['ai_auto_summarize']) || !class_exists('OpenTrust_Chat_Summarizer')) { + if (!$has_active_key || empty($settings['ai_auto_summarize']) || !class_exists('Ettic_OTC_Chat_Summarizer')) { return; } - $missing = OpenTrust_Chat_Summarizer::missing_summary_count(); + $missing = Ettic_OTC_Chat_Summarizer::missing_summary_count(); if ($missing < 1) { return; } @@ -179,7 +179,7 @@ private function render_summary_backfill_banner(array $settings, bool $has_activ } private function render_ai_provider_picker(array $settings, array $stored_keys): void { - $providers = OpenTrust_Chat_Provider::available(); + $providers = Ettic_OTC_Chat_Provider::available(); $active_provider = $settings['ai_provider'] ?? ''; // Partition: Anthropic is the primary, everything else is "advanced". @@ -251,7 +251,7 @@ private function render_provider_card(array $provider, array $stored_keys, strin $key_url = (string) $provider['key_url']; $is_active = $slug === $active_provider; $has_key = isset($stored_keys[$slug]); - $masked = $has_key ? OpenTrust_Chat_Secrets::mask($stored_keys[$slug]) : ''; + $masked = $has_key ? Ettic_OTC_Chat_Secrets::mask($stored_keys[$slug]) : ''; $card_classes = ['ot-ai-card', 'ot-ai-card--' . $variant]; if ($is_active) { @@ -409,14 +409,14 @@ private function render_ai_settings_form(array $settings): void { - +

- +

@@ -435,7 +435,7 @@ private function render_ai_settings_form(array $settings): void { - + @@ -480,8 +480,8 @@ private function render_ai_settings_form(array $settings): void { - - + + @@ -555,7 +555,7 @@ private function cached_models_for(string $provider): array { if ($provider === '') { return []; } - $stored_keys = OpenTrust_Chat_Secrets::get_all(); + $stored_keys = Ettic_OTC_Chat_Secrets::get_all(); if (!isset($stored_keys[$provider])) { return []; } @@ -566,7 +566,7 @@ private function cached_models_for(string $provider): array { } private function cache_key_for(string $provider, string $api_key): string { - return 'opentrust_models_' . $provider . '_' . OpenTrust_Chat_Secrets::fingerprint($api_key); + return 'opentrust_models_' . $provider . '_' . Ettic_OTC_Chat_Secrets::fingerprint($api_key); } /** @@ -633,7 +633,7 @@ public function snapshot_active_model(array &$settings, array $models): void { * @return array{ok: bool, models?: array, error?: string} */ private function refresh_provider_cache(string $slug, string $api_key): array { - $adapter = OpenTrust_Chat_Provider::for($slug); + $adapter = Ettic_OTC_Chat_Provider::for($slug); if (!$adapter) { return ['ok' => false, 'error' => 'Unknown provider']; } @@ -661,7 +661,7 @@ public function handle_ai_save_key(): void { $provider = isset($_POST['provider']) ? sanitize_key((string) wp_unslash($_POST['provider'])) : ''; $api_key = isset($_POST['api_key']) ? trim(sanitize_text_field((string) wp_unslash($_POST['api_key']))) : ''; - $adapter = OpenTrust_Chat_Provider::for($provider); + $adapter = Ettic_OTC_Chat_Provider::for($provider); if (!$adapter) { $this->ai_notice('error', __('Unknown provider.', 'opentrust')); $this->redirect_to_ai_tab(); @@ -681,11 +681,11 @@ public function handle_ai_save_key(): void { $this->redirect_to_ai_tab(); } - OpenTrust_Chat_Secrets::put($provider, $api_key); + Ettic_OTC_Chat_Secrets::put($provider, $api_key); // Update settings: mark AI enabled, record provider + cache timestamp, // and if no model is selected yet, pre-pick the first recommended model. - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); $settings['ai_enabled'] = true; $settings['ai_provider'] = $provider; $settings['ai_model_list_cached_at'] = time(); @@ -701,7 +701,7 @@ public function handle_ai_save_key(): void { } } $this->snapshot_active_model($settings, $result['models']); - OpenTrust_Admin_Settings::instance()->save_settings_raw($settings); + Ettic_OTC_Admin_Settings::instance()->save_settings_raw($settings); /* translators: 1: provider label, 2: number of models */ $count_msg = sprintf(__('%1$s key validated. Found %2$d model(s).', 'opentrust'), $adapter->label(), count($result['models'])); @@ -717,29 +717,29 @@ public function handle_ai_forget_key(): void { $provider = isset($_POST['provider']) ? sanitize_key((string) wp_unslash($_POST['provider'])) : ''; - $adapter = OpenTrust_Chat_Provider::for($provider); + $adapter = Ettic_OTC_Chat_Provider::for($provider); if (!$adapter) { $this->ai_notice('error', __('Unknown provider.', 'opentrust')); $this->redirect_to_ai_tab(); } // Clear cached model list for this key before forgetting. - $existing = OpenTrust_Chat_Secrets::get($provider); + $existing = Ettic_OTC_Chat_Secrets::get($provider); if ($existing !== null) { - $fingerprint = OpenTrust_Chat_Secrets::fingerprint($existing); + $fingerprint = Ettic_OTC_Chat_Secrets::fingerprint($existing); delete_transient('opentrust_models_' . $provider . '_' . $fingerprint); } - OpenTrust_Chat_Secrets::forget($provider); + Ettic_OTC_Chat_Secrets::forget($provider); // If the forgotten provider was the active one, disable chat and clear the model. - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); if (($settings['ai_provider'] ?? '') === $provider) { $settings['ai_enabled'] = false; $settings['ai_provider'] = ''; $settings['ai_model'] = ''; $settings['ai_model_list_cached_at'] = 0; - OpenTrust_Admin_Settings::instance()->save_settings_raw($settings); + Ettic_OTC_Admin_Settings::instance()->save_settings_raw($settings); } $this->ai_notice('success', __('Key removed.', 'opentrust')); @@ -753,13 +753,13 @@ public function handle_ai_refresh_models(): void { check_admin_referer('opentrust_ai_refresh_models'); $provider = isset($_GET['provider']) ? sanitize_key((string) wp_unslash($_GET['provider'])) : ''; - $adapter = OpenTrust_Chat_Provider::for($provider); + $adapter = Ettic_OTC_Chat_Provider::for($provider); if (!$adapter) { $this->ai_notice('error', __('Unknown provider.', 'opentrust')); $this->redirect_to_ai_tab(); } - $api_key = OpenTrust_Chat_Secrets::get($provider); + $api_key = Ettic_OTC_Chat_Secrets::get($provider); if ($api_key === null) { $this->ai_notice('error', __('No key on file for this provider.', 'opentrust')); $this->redirect_to_ai_tab(); @@ -773,10 +773,10 @@ public function handle_ai_refresh_models(): void { $this->redirect_to_ai_tab(); } - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); $settings['ai_model_list_cached_at'] = time(); $this->snapshot_active_model($settings, $result['models']); - OpenTrust_Admin_Settings::instance()->save_settings_raw($settings); + Ettic_OTC_Admin_Settings::instance()->save_settings_raw($settings); /* translators: %d: number of models */ $this->ai_notice('success', sprintf(__('Model list refreshed. Found %d model(s).', 'opentrust'), count($result['models']))); @@ -798,8 +798,8 @@ public function handle_ai_summarize_sweep(): void { check_admin_referer('opentrust_ai_summarize_sweep'); $count = 0; - if (class_exists('OpenTrust_Chat_Summarizer')) { - $count = OpenTrust_Chat_Summarizer::sweep_all(); + if (class_exists('Ettic_OTC_Chat_Summarizer')) { + $count = Ettic_OTC_Chat_Summarizer::sweep_all(); } set_transient( @@ -862,15 +862,15 @@ public static function unschedule_cron(): void { * others. */ public static function cron_refresh_all_providers(): void { - $stored_keys = OpenTrust_Chat_Secrets::get_all(); + $stored_keys = Ettic_OTC_Chat_Secrets::get_all(); if (empty($stored_keys)) { return; } $self = self::instance(); - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); $active = (string) ($settings['ai_provider'] ?? ''); - $log = static fn(string $slug, string $why) => OpenTrust::debug_log("AI model refresh failed for {$slug}: {$why}"); + $log = static fn(string $slug, string $why) => Ettic_OTC::debug_log("AI model refresh failed for {$slug}: {$why}"); $dirty = false; foreach ($stored_keys as $slug => $api_key) { @@ -892,10 +892,10 @@ public static function cron_refresh_all_providers(): void { } if ($dirty) { - OpenTrust_Admin_Settings::instance()->save_settings_raw($settings); + Ettic_OTC_Admin_Settings::instance()->save_settings_raw($settings); } } } // Wire the cron hook at file load so it fires regardless of admin context. -add_action(OpenTrust_Admin_AI::CRON_HOOK, [OpenTrust_Admin_AI::class, 'cron_refresh_all_providers']); +add_action(Ettic_OTC_Admin_AI::CRON_HOOK, [Ettic_OTC_Admin_AI::class, 'cron_refresh_all_providers']); diff --git a/includes/class-opentrust-admin-questions.php b/includes/class-ettic-otc-admin-questions.php similarity index 96% rename from includes/class-opentrust-admin-questions.php rename to includes/class-ettic-otc-admin-questions.php index 29580c9..8fb9c15 100644 --- a/includes/class-opentrust-admin-questions.php +++ b/includes/class-ettic-otc-admin-questions.php @@ -4,13 +4,13 @@ * admin-post handlers that drive its toolbar (CSV export, full clear, * logging toggle). * - * Lives on its own submenu under the OpenTrust top-level menu. Visibility - * of that submenu is gated in OpenTrust_Admin::register_menu() on the + * Lives on its own submenu under the Ettic_OTC top-level menu. Visibility + * of that submenu is gated in Ettic_OTC_Admin::register_menu() on the * `ai_enabled` setting. Once the submenu is registered, this class owns * the page render and all handler endpoints. * * Identifiers in the underlying log table are pre-hashed by - * OpenTrust_Chat_Log; nothing in this screen surfaces raw IPs/sessions. + * Ettic_OTC_Chat_Log; nothing in this screen surfaces raw IPs/sessions. */ declare(strict_types=1); @@ -19,7 +19,7 @@ exit; } -final class OpenTrust_Admin_Questions { +final class Ettic_OTC_Admin_Questions { private static ?self $instance = null; @@ -42,7 +42,7 @@ public function render_page(): void { return; } - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Read-only filter params on admin display page. $filters = [ @@ -55,12 +55,12 @@ public function render_page(): void { ]; // phpcs:enable WordPress.Security.NonceVerification.Recommended - $result = OpenTrust_Chat_Log::query($filters); + $result = Ettic_OTC_Chat_Log::query($filters); $total = $result['total']; $rows = $result['rows']; $pages = max(1, (int) ceil($total / $filters['per_page'])); - $models = OpenTrust_Chat_Log::distinct_models(); - $counts = OpenTrust_Chat_Log::total_count(); + $models = Ettic_OTC_Chat_Log::distinct_models(); + $counts = Ettic_OTC_Chat_Log::total_count(); $export_url = wp_nonce_url( admin_url('admin-post.php?action=opentrust_ai_questions_export&' . http_build_query(array_filter($filters + ['paged' => 0]))), @@ -233,7 +233,7 @@ public function handle_export(): void { 'per_page' => 10000, // hard cap — nobody exports >10k rows per page ]; - $result = OpenTrust_Chat_Log::query($filters); + $result = Ettic_OTC_Chat_Log::query($filters); header('Content-Type: text/csv; charset=utf-8'); header('Content-Disposition: attachment; filename=opentrust-questions-' . gmdate('Y-m-d') . '.csv'); @@ -265,7 +265,7 @@ public function handle_clear(): void { } check_admin_referer('opentrust_ai_questions_clear'); - OpenTrust_Chat_Log::clear_all(); + Ettic_OTC_Chat_Log::clear_all(); set_transient( 'opentrust_ai_notice_' . get_current_user_id(), @@ -282,9 +282,9 @@ public function handle_toggle_logging(): void { } check_admin_referer('opentrust_ai_toggle_logging'); - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); $settings['ai_logging_enabled'] = empty($settings['ai_logging_enabled']); - OpenTrust_Admin_Settings::instance()->save_settings_raw($settings); + Ettic_OTC_Admin_Settings::instance()->save_settings_raw($settings); set_transient( 'opentrust_ai_notice_' . get_current_user_id(), diff --git a/includes/class-opentrust-admin-review.php b/includes/class-ettic-otc-admin-review.php similarity index 95% rename from includes/class-opentrust-admin-review.php rename to includes/class-ettic-otc-admin-review.php index 7a0558a..7059da3 100644 --- a/includes/class-opentrust-admin-review.php +++ b/includes/class-ettic-otc-admin-review.php @@ -4,7 +4,7 @@ * * A small, opt-out-able nudge asking long-time admins to leave a rating on * the WordPress.org plugin directory. Two surfaces, both scoped strictly to - * OpenTrust admin screens (never the dashboard, plugin list, or other + * Ettic_OTC admin screens (never the dashboard, plugin list, or other * plugins' pages): * * 1. Footer text — replaces the default "Thank you for creating with @@ -28,7 +28,7 @@ exit; } -final class OpenTrust_Admin_Review { +final class Ettic_OTC_Admin_Review { private const DISMISS_META_KEY = '_opentrust_review_dismissed_v1'; private const FIRST_SEEN_OPTION = 'opentrust_first_activated_at'; @@ -86,7 +86,7 @@ public function footer_text(string $text): string { // the result — same risk model as core's admin_footer_text usage. return sprintf( /* translators: %s: link to the WordPress.org reviews page */ - __('OpenTrust is built and maintained in the open. If it is helping your team, a %s keeps the project moving.', 'opentrust'), + __('Ettic_OTC is built and maintained in the open. If it is helping your team, a %s keeps the project moving.', 'opentrust'), $link ); } @@ -113,7 +113,7 @@ public function render_milestone_notice(): void {

- +

@@ -152,7 +152,7 @@ private function should_show_milestone_notice(): bool { return false; } - $counts = wp_count_posts(OpenTrust_CPT::POLICY); + $counts = wp_count_posts(Ettic_OTC_CPT::POLICY); $published = (int) ($counts->publish ?? 0); return $published >= self::POLICY_THRESHOLD; @@ -191,7 +191,7 @@ public function handle_dismiss(): void { /** * Match the scoping rule used by render_plain_permalinks_notice in - * OpenTrust_Admin: any screen whose id contains "opentrust" plus the + * Ettic_OTC_Admin: any screen whose id contains "opentrust" plus the * five content CPTs. Identical pattern keeps both notices in lockstep. */ private static function is_opentrust_screen(): bool { @@ -204,7 +204,7 @@ private static function is_opentrust_screen(): bool { } return str_contains((string) $screen->id, 'opentrust') - || in_array($screen->post_type, OpenTrust_CPT::CORPUS, true); + || in_array($screen->post_type, Ettic_OTC_CPT::CORPUS, true); } private static function review_url(): string { diff --git a/includes/class-opentrust-admin-settings.php b/includes/class-ettic-otc-admin-settings.php similarity index 94% rename from includes/class-opentrust-admin-settings.php rename to includes/class-ettic-otc-admin-settings.php index 7b300fa..64c9bf0 100644 --- a/includes/class-opentrust-admin-settings.php +++ b/includes/class-ettic-otc-admin-settings.php @@ -3,15 +3,15 @@ * Settings API registration, field rendering, sanitization, and the * settings-page wrapper that hosts the General / Contact / AI tabs. * - * Owns the entire WordPress Settings API surface for OpenTrust: + * Owns the entire WordPress Settings API surface for Ettic_OTC: * register_setting() with a sanitize_callback, every add_settings_section * and add_settings_field call, the eight per-type field renderers, and * the schema-driven sanitize cascade that keeps cross-tab saves shape- * stable. * - * Bootstrapped by OpenTrust_Admin's constructor; subscribes its own + * Bootstrapped by Ettic_OTC_Admin's constructor; subscribes its own * admin_init hook for register_settings(). The settings menu page in - * OpenTrust_Admin::register_menu() points its callback directly at this + * Ettic_OTC_Admin::register_menu() points its callback directly at this * class's render_settings_page(). * * Also owns save_settings_raw() — the skip-sanitize writer used by the @@ -26,7 +26,7 @@ exit; } -final class OpenTrust_Admin_Settings { +final class Ettic_OTC_Admin_Settings { private static ?self $instance = null; @@ -46,7 +46,7 @@ public function register_settings(): void { register_setting('opentrust_settings_group', 'opentrust_settings', [ 'type' => 'array', 'sanitize_callback' => [$this, 'sanitize_settings'], - 'default' => OpenTrust::defaults(), + 'default' => Ettic_OTC::defaults(), ]); // ── General tab ────────────────────────────────────────────── @@ -184,7 +184,7 @@ public function render_textarea_field(array $args): void { * @param array $extra_attrs */ private function render_input_field(string $type, array $args, array $extra_attrs = []): void { - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); $key = $args['key']; $value = $settings[$key] ?? ''; @@ -208,7 +208,7 @@ private function render_input_field(string $type, array $args, array $extra_attr } public function render_color_field(array $args): void { - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); $value = $settings['accent_color'] ?? '#2563EB'; $force_exact = !empty($settings['accent_force_exact']); printf( @@ -223,7 +223,7 @@ public function render_color_field(array $args): void {

- +

@@ -276,7 +276,7 @@ public function render_avatar_field(array $args): void { } private function render_media_field(string $key, string $button_label, string $description): void { - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); $media_id = (int) ($settings[$key] ?? 0); $media_url = $media_id ? wp_get_attachment_image_url($media_id, 'medium') : ''; ?> @@ -293,12 +293,12 @@ private function render_media_field(string $key, string $button_label, string $d } public function render_show_powered_by_field(array $args): void { - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); $checked = !empty($settings['show_powered_by']); printf( '', checked($checked, true, false), - esc_html__('Show a "Powered by OpenTrust" credit in the trust center footer.', 'opentrust') + esc_html__('Show a "Powered by Open Trust Center" credit in the trust center footer.', 'opentrust') ); printf( '

%s

', @@ -307,7 +307,7 @@ public function render_show_powered_by_field(array $args): void { } public function render_sections_field(array $args): void { - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); $visible = $settings['sections_visible'] ?? []; $sections = [ @@ -336,10 +336,10 @@ public function render_sections_field(array $args): void { public function sanitize_settings(mixed $input): array { if (!is_array($input)) { - return OpenTrust::defaults(); + return Ettic_OTC::defaults(); } - $old = OpenTrust::get_settings(); + $old = Ettic_OTC::get_settings(); $sanitized = []; // Schema-driven dispatch. Each tab's form carries a save sentinel @@ -368,7 +368,7 @@ public function sanitize_settings(mixed $input): array { $sanitized['ai_model_display_name'] = (string) ($old['ai_model_display_name'] ?? ''); $sanitized['ai_model_recommended'] = !empty($old['ai_model_recommended']); if (($sanitized['ai_model'] ?? '') !== ($old['ai_model'] ?? '')) { - $snap = OpenTrust_Admin_AI::instance()->snapshot_for_provider( + $snap = Ettic_OTC_Admin_AI::instance()->snapshot_for_provider( $sanitized['ai_provider'], (string) ($sanitized['ai_model'] ?? '') ); @@ -378,7 +378,7 @@ public function sanitize_settings(mixed $input): array { } } - // Per-site salt — written out-of-band by OpenTrust_Chat_Budget::site_salt(). + // Per-site salt — written out-of-band by Ettic_OTC_Chat_Budget::site_salt(). // Carry forward byte-for-byte so saving settings doesn't force a // regeneration (which would invalidate all in-flight rate-limit // hashes and Turnstile bypass transients). @@ -442,8 +442,8 @@ private static function settings_schema(): array { // ── General tab ── 'endpoint_slug' => [ 'tab' => 'general', - 'default' => OpenTrust::DEFAULT_ENDPOINT_SLUG, - 'sanitize' => static fn($v) => sanitize_title((string) ($v ?? '')) ?: OpenTrust::DEFAULT_ENDPOINT_SLUG, + 'default' => Ettic_OTC::DEFAULT_ENDPOINT_SLUG, + 'sanitize' => static fn($v) => sanitize_title((string) ($v ?? '')) ?: Ettic_OTC::DEFAULT_ENDPOINT_SLUG, ], 'page_title' => ['tab' => 'general', 'default' => '', 'sanitize' => $string], 'company_name' => ['tab' => 'general', 'default' => '', 'sanitize' => $string], @@ -485,28 +485,28 @@ private static function settings_schema(): array { 'ai_model' => ['tab' => 'ai', 'default' => '', 'sanitize' => $string], 'ai_daily_token_budget' => [ 'tab' => 'ai', - 'default' => OpenTrust_Chat_Budget::DEFAULT_DAILY_TOKEN_BUDGET, - 'sanitize' => static fn($v): int => max(0, absint($v ?? OpenTrust_Chat_Budget::DEFAULT_DAILY_TOKEN_BUDGET)), + 'default' => Ettic_OTC_Chat_Budget::DEFAULT_DAILY_TOKEN_BUDGET, + 'sanitize' => static fn($v): int => max(0, absint($v ?? Ettic_OTC_Chat_Budget::DEFAULT_DAILY_TOKEN_BUDGET)), ], 'ai_monthly_token_budget' => [ 'tab' => 'ai', - 'default' => OpenTrust_Chat_Budget::DEFAULT_MONTHLY_TOKEN_BUDGET, - 'sanitize' => static fn($v): int => max(0, absint($v ?? OpenTrust_Chat_Budget::DEFAULT_MONTHLY_TOKEN_BUDGET)), + 'default' => Ettic_OTC_Chat_Budget::DEFAULT_MONTHLY_TOKEN_BUDGET, + 'sanitize' => static fn($v): int => max(0, absint($v ?? Ettic_OTC_Chat_Budget::DEFAULT_MONTHLY_TOKEN_BUDGET)), ], 'ai_rate_limit_per_ip' => [ 'tab' => 'ai', - 'default' => OpenTrust_Chat_Budget::DEFAULT_RATE_LIMIT_PER_IP, - 'sanitize' => $bounded_int(0, 1000, OpenTrust_Chat_Budget::DEFAULT_RATE_LIMIT_PER_IP), + 'default' => Ettic_OTC_Chat_Budget::DEFAULT_RATE_LIMIT_PER_IP, + 'sanitize' => $bounded_int(0, 1000, Ettic_OTC_Chat_Budget::DEFAULT_RATE_LIMIT_PER_IP), ], 'ai_rate_limit_per_session' => [ 'tab' => 'ai', - 'default' => OpenTrust_Chat_Budget::DEFAULT_RATE_LIMIT_PER_SESSION, - 'sanitize' => $bounded_int(0, 10000, OpenTrust_Chat_Budget::DEFAULT_RATE_LIMIT_PER_SESSION), + 'default' => Ettic_OTC_Chat_Budget::DEFAULT_RATE_LIMIT_PER_SESSION, + 'sanitize' => $bounded_int(0, 10000, Ettic_OTC_Chat_Budget::DEFAULT_RATE_LIMIT_PER_SESSION), ], 'ai_max_message_length' => [ 'tab' => 'ai', - 'default' => OpenTrust_Chat::DEFAULT_MAX_MESSAGE_LENGTH, - 'sanitize' => $bounded_int(100, 4000, OpenTrust_Chat::DEFAULT_MAX_MESSAGE_LENGTH), + 'default' => Ettic_OTC_Chat::DEFAULT_MAX_MESSAGE_LENGTH, + 'sanitize' => $bounded_int(100, 4000, Ettic_OTC_Chat::DEFAULT_MAX_MESSAGE_LENGTH), ], 'ai_contact_url' => ['tab' => 'ai', 'default' => '', 'sanitize' => $url], 'ai_show_model_attribution' => ['tab' => 'ai', 'default' => false, 'sanitize' => $bool], @@ -538,11 +538,11 @@ private static function settings_schema(): array { * ciphertext) → return as-is. * * Anything else is text-sanitized and then encrypted via - * OpenTrust_Chat_Secrets, so the option never carries the plaintext. + * Ettic_OTC_Chat_Secrets, so the option never carries the plaintext. */ private static function sanitize_secret_field(string $new_value, string $old_value): string { // Idempotency: already-encrypted ciphertext passes through. Stored - // values created by OpenTrust_Chat_Secrets::encrypt() always carry + // values created by Ettic_OTC_Chat_Secrets::encrypt() always carry // this prefix, so trusting it here costs nothing real-world. if (str_starts_with($new_value, 'ot_enc_v1:')) { return $new_value; @@ -557,7 +557,7 @@ private static function sanitize_secret_field(string $new_value, string $old_val if ($clean === '') { return $old_value; } - return OpenTrust_Chat_Secrets::encrypt($clean); + return Ettic_OTC_Chat_Secrets::encrypt($clean); } // ────────────────────────────────────────────── @@ -569,8 +569,8 @@ public function render_settings_page(): void { return; } - $settings = OpenTrust::get_settings(); - $tc_url = home_url('/' . ($settings['endpoint_slug'] ?? OpenTrust::DEFAULT_ENDPOINT_SLUG) . '/'); + $settings = Ettic_OTC::get_settings(); + $tc_url = home_url('/' . ($settings['endpoint_slug'] ?? Ettic_OTC::DEFAULT_ENDPOINT_SLUG) . '/'); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only tab switch on admin settings page. $tab = isset($_GET['tab']) ? sanitize_key((string) wp_unslash($_GET['tab'])) : 'general'; if (!in_array($tab, ['general', 'contact', 'ai', 'io'], true)) { @@ -612,9 +612,9 @@ class="nav-tab "> - render_tab(); ?> + render_tab(); ?> - render_ai_tab($settings); ?> + render_ai_tab($settings); ?>

%s

', esc_attr($class), wp_kses_post((string) $notice['message'])); } - $exportable = OpenTrust_IO::exportable_summary(); + $exportable = Ettic_OTC_IO::exportable_summary(); ?>

@@ -281,7 +281,7 @@ private function render_import_panel(): void { private function render_preview_screen(array $preview): void { $action_url = admin_url('admin-post.php'); $manifest_format = (string) ($preview['manifest']['format'] ?? ''); - $is_settings = $manifest_format === OpenTrust_IO::FORMAT_SETTINGS; + $is_settings = $manifest_format === Ettic_OTC_IO::FORMAT_SETTINGS; $totals = ['create' => 0, 'update' => 0, 'skip' => 0]; foreach ($preview['summary'] ?? [] as $row) { foreach ($totals as $k => $_) { @@ -377,7 +377,7 @@ public function handle_export(): void { try { if ($kind === 'settings') { - $manifest = OpenTrust_IO::build_settings_manifest($include_media); + $manifest = Ettic_OTC_IO::build_settings_manifest($include_media); $prefix = 'opentrust-settings'; } else { $selection = $this->parse_selection($_POST); @@ -385,11 +385,11 @@ public function handle_export(): void { $this->bounce_error(__('Pick at least one record to export.', 'opentrust')); return; } - $manifest = OpenTrust_IO::build_content_manifest($selection, $include_media); + $manifest = Ettic_OTC_IO::build_content_manifest($selection, $include_media); $prefix = 'opentrust-content'; } - $zip_path = OpenTrust_IO::write_zip($manifest, $prefix); + $zip_path = Ettic_OTC_IO::write_zip($manifest, $prefix); } catch (\Throwable $e) { $this->bounce_error($e->getMessage()); return; @@ -457,11 +457,11 @@ public function handle_import_preview(): void { $stash_path = (string) $upload['file']; try { - $read = OpenTrust_IO::read_zip($stash_path); + $read = Ettic_OTC_IO::read_zip($stash_path); $manifest = $read['manifest']; - $check = OpenTrust_IO::validate_manifest($manifest); + $check = Ettic_OTC_IO::validate_manifest($manifest); - $strategy = isset($_POST['opentrust_strategy']) ? sanitize_key((string) wp_unslash($_POST['opentrust_strategy'])) : OpenTrust_IO::STRATEGY_SKIP; + $strategy = isset($_POST['opentrust_strategy']) ? sanitize_key((string) wp_unslash($_POST['opentrust_strategy'])) : Ettic_OTC_IO::STRATEGY_SKIP; $preview = [ 'manifest' => $manifest, @@ -473,8 +473,8 @@ public function handle_import_preview(): void { 'records' => [], ]; - if (($manifest['format'] ?? '') === OpenTrust_IO::FORMAT_CONTENT && empty($check['errors'])) { - $diff = OpenTrust_IO::preview_import($manifest, $strategy); + if (($manifest['format'] ?? '') === Ettic_OTC_IO::FORMAT_CONTENT && empty($check['errors'])) { + $diff = Ettic_OTC_IO::preview_import($manifest, $strategy); $preview['summary'] = $diff['summary']; $preview['records'] = $diff['records']; } @@ -522,18 +522,18 @@ public function handle_import_apply(): void { $zip_path = (string) ($preview['zip_path'] ?? ''); $manifest = (array) ($preview['manifest'] ?? []); - $strategy = (string) ($preview['strategy'] ?? OpenTrust_IO::STRATEGY_SKIP); + $strategy = (string) ($preview['strategy'] ?? Ettic_OTC_IO::STRATEGY_SKIP); try { - if (($manifest['format'] ?? '') === OpenTrust_IO::FORMAT_SETTINGS) { - $result = OpenTrust_IO::apply_settings_import($manifest, $zip_path); + if (($manifest['format'] ?? '') === Ettic_OTC_IO::FORMAT_SETTINGS) { + $result = Ettic_OTC_IO::apply_settings_import($manifest, $zip_path); $msg = sprintf( /* translators: %d: count */ _n('%d setting imported.', '%d settings imported.', (int) ($result['updated'] ?? 0), 'opentrust'), (int) ($result['updated'] ?? 0) ); } else { - $result = OpenTrust_IO::apply_content_import($manifest, $zip_path, $strategy); + $result = Ettic_OTC_IO::apply_content_import($manifest, $zip_path, $strategy); $msg = sprintf( /* translators: %1$d: created, %2$d: updated, %3$d: skipped */ __('Imported: %1$d created, %2$d updated, %3$d skipped.', 'opentrust'), @@ -574,7 +574,7 @@ private function parse_selection(array $post): array { $out = []; foreach ($cpts as $cpt => $_) { $cpt = sanitize_key((string) $cpt); - if (!in_array($cpt, OpenTrust_CPT::ALL, true)) continue; + if (!in_array($cpt, Ettic_OTC_CPT::ALL, true)) continue; $picked = isset($ids[$cpt]) && is_array($ids[$cpt]) ? array_values(array_filter(array_map('intval', $ids[$cpt]))) @@ -589,11 +589,11 @@ private function parse_selection(array $post): array { private function cpt_label(string $cpt): string { return match ($cpt) { - OpenTrust_CPT::POLICY => __('Policies', 'opentrust'), - OpenTrust_CPT::CERTIFICATION => __('Certifications', 'opentrust'), - OpenTrust_CPT::SUBPROCESSOR => __('Subprocessors', 'opentrust'), - OpenTrust_CPT::DATA_PRACTICE => __('Data Practices', 'opentrust'), - OpenTrust_CPT::FAQ => __('FAQs', 'opentrust'), + Ettic_OTC_CPT::POLICY => __('Policies', 'opentrust'), + Ettic_OTC_CPT::CERTIFICATION => __('Certifications', 'opentrust'), + Ettic_OTC_CPT::SUBPROCESSOR => __('Subprocessors', 'opentrust'), + Ettic_OTC_CPT::DATA_PRACTICE => __('Data Practices', 'opentrust'), + Ettic_OTC_CPT::FAQ => __('FAQs', 'opentrust'), default => $cpt, }; } diff --git a/includes/class-opentrust-admin.php b/includes/class-ettic-otc-admin.php similarity index 85% rename from includes/class-opentrust-admin.php rename to includes/class-ettic-otc-admin.php index a00c926..dd472a3 100644 --- a/includes/class-opentrust-admin.php +++ b/includes/class-ettic-otc-admin.php @@ -2,13 +2,13 @@ /** * Admin bootstrap. * - * Slim orchestrator that wires up the OpenTrust top-level admin menu, + * Slim orchestrator that wires up the Ettic_OTC top-level admin menu, * the per-screen asset enqueue, the "Plain permalinks" warning, and the * three sub-admin classes that own the actual screens: * - * - OpenTrust_Admin_Settings — Settings API + General/Contact/AI tabs page render - * - OpenTrust_Admin_AI — AI tab body + key save/forget/refresh handlers - * - OpenTrust_Admin_Questions — Questions log screen + export/clear/toggle + * - Ettic_OTC_Admin_Settings — Settings API + General/Contact/AI tabs page render + * - Ettic_OTC_Admin_AI — AI tab body + key save/forget/refresh handlers + * - Ettic_OTC_Admin_Questions — Questions log screen + export/clear/toggle * * Each sub-admin owns its own hook subscriptions; this class only owns * menu/asset/notice scaffolding that is shared across all of them. @@ -20,7 +20,7 @@ exit; } -final class OpenTrust_Admin { +final class Ettic_OTC_Admin { private static ?self $instance = null; @@ -33,16 +33,16 @@ private function __construct() { add_action('admin_enqueue_scripts', [$this, 'enqueue_assets']); add_filter('submenu_file', [$this, 'fix_submenu_highlight']); - // Warn admins on every OpenTrust admin page when the site is on Plain + // Warn admins on every Ettic_OTC admin page when the site is on Plain // permalinks — the plugin's pretty URLs all 404 in that mode. add_action('admin_notices', [$this, 'render_plain_permalinks_notice']); // Sub-admin systems own their own hooks. - OpenTrust_Admin_Settings::instance(); - OpenTrust_Admin_Questions::instance(); - OpenTrust_Admin_AI::instance(); - OpenTrust_Admin_Review::instance(); - OpenTrust_Admin_Tools::instance(); + Ettic_OTC_Admin_Settings::instance(); + Ettic_OTC_Admin_Questions::instance(); + Ettic_OTC_Admin_AI::instance(); + Ettic_OTC_Admin_Review::instance(); + Ettic_OTC_Admin_Tools::instance(); } // ────────────────────────────────────────────── @@ -50,11 +50,11 @@ private function __construct() { // ────────────────────────────────────────────── public function register_menu(): void { - $settings_page = [OpenTrust_Admin_Settings::instance(), 'render_settings_page']; + $settings_page = [Ettic_OTC_Admin_Settings::instance(), 'render_settings_page']; add_menu_page( - __('OpenTrust', 'opentrust'), - __('OpenTrust', 'opentrust'), + __('Open Trust Center', 'opentrust'), + __('Open Trust Center', 'opentrust'), 'manage_options', 'opentrust', $settings_page, @@ -72,7 +72,7 @@ public function register_menu(): void { ); // AI Questions — only visible once AI is enabled. - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); if (!empty($settings['ai_enabled'])) { add_submenu_page( 'opentrust', @@ -80,7 +80,7 @@ public function register_menu(): void { __('Questions', 'opentrust'), 'manage_options', 'opentrust-questions', - [OpenTrust_Admin_Questions::instance(), 'render_page'] + [Ettic_OTC_Admin_Questions::instance(), 'render_page'] ); } } @@ -104,7 +104,7 @@ public function fix_submenu_highlight(?string $submenu_file): ?string { return $submenu_file; } - if (in_array($post_type, OpenTrust_CPT::ALL, true)) { + if (in_array($post_type, Ettic_OTC_CPT::ALL, true)) { return "edit.php?post_type={$post_type}"; } @@ -124,7 +124,7 @@ public function enqueue_assets(string $hook): void { $is_opentrust_screen = str_starts_with($screen->id, 'toplevel_page_opentrust') || str_starts_with($screen->id, 'opentrust_page_') - || in_array($screen->post_type, OpenTrust_CPT::CORPUS, true); + || in_array($screen->post_type, Ettic_OTC_CPT::CORPUS, true); if (!$is_opentrust_screen) { return; @@ -135,16 +135,16 @@ public function enqueue_assets(string $hook): void { wp_enqueue_style( 'opentrust-admin', - OPENTRUST_PLUGIN_URL . 'assets/css/admin.css', + ETTIC_OTC_PLUGIN_URL . 'assets/css/admin.css', [], - OPENTRUST_VERSION + ETTIC_OTC_VERSION ); wp_enqueue_script( 'opentrust-admin', - OPENTRUST_PLUGIN_URL . 'assets/js/admin.js', + ETTIC_OTC_PLUGIN_URL . 'assets/js/admin.js', ['wp-color-picker', 'jquery'], - OPENTRUST_VERSION, + ETTIC_OTC_VERSION, true ); @@ -170,10 +170,10 @@ public function enqueue_assets(string $hook): void { // the new-post screen for the two CPTs that support it. Edit screens // are deliberately excluded so we never stomp existing values. $screen = get_current_screen(); - if ($hook === 'post-new.php' && $screen && in_array($screen->post_type, [OpenTrust_CPT::SUBPROCESSOR, OpenTrust_CPT::DATA_PRACTICE, OpenTrust_CPT::CERTIFICATION], true)) { + if ($hook === 'post-new.php' && $screen && in_array($screen->post_type, [Ettic_OTC_CPT::SUBPROCESSOR, Ettic_OTC_CPT::DATA_PRACTICE, Ettic_OTC_CPT::CERTIFICATION], true)) { $payload = [ 'postType' => $screen->post_type, - 'catalog' => OpenTrust_Catalog::for_js($screen->post_type), + 'catalog' => Ettic_OTC_Catalog::for_js($screen->post_type), 'i18n' => [ 'noMatchHint' => __('No match in catalog, just keep typing to add manually.', 'opentrust'), 'helpFact' => __('Auto-filled from catalog, you may want to verify this.', 'opentrust'), @@ -195,7 +195,7 @@ public function enqueue_assets(string $hook): void { // ────────────────────────────────────────────── /** - * Show a persistent warning on every OpenTrust admin screen when the + * Show a persistent warning on every Ettic_OTC admin screen when the * WordPress permalink structure is "Plain" (i.e. empty). In that mode * all of the plugin's pretty URLs (/trust-center/, /trust-center/policy/..., * /trust-center/ask/) return 404. @@ -210,11 +210,11 @@ public function render_plain_permalinks_notice(): void { return; } - // Limit the noise to OpenTrust-owned screens: top-level plugin pages, + // Limit the noise to Ettic_OTC-owned screens: top-level plugin pages, // subpages, and the four content CPTs. Bail on every other admin screen. $is_opentrust_screen = str_contains((string) $screen->id, 'opentrust') || - in_array($screen->post_type, OpenTrust_CPT::CORPUS, true); + in_array($screen->post_type, Ettic_OTC_CPT::CORPUS, true); if (!$is_opentrust_screen) { return; @@ -225,7 +225,7 @@ public function render_plain_permalinks_notice(): void { ?>

- +

- +

diff --git a/includes/class-opentrust-catalog.php b/includes/class-ettic-otc-catalog.php similarity index 96% rename from includes/class-opentrust-catalog.php rename to includes/class-ettic-otc-catalog.php index 97f2c83..afe715f 100644 --- a/includes/class-opentrust-catalog.php +++ b/includes/class-ettic-otc-catalog.php @@ -28,7 +28,7 @@ exit; } -final class OpenTrust_Catalog { +final class Ettic_OTC_Catalog { /** * Return the normalized subprocessor catalog. @@ -72,7 +72,7 @@ private static function load_catalog( string $file_basename, string $filter_name return $cache[ $file_basename ]; } - $raw = require OPENTRUST_PLUGIN_DIR . 'includes/data/' . $file_basename; + $raw = require ETTIC_OTC_PLUGIN_DIR . 'includes/data/' . $file_basename; $raw = is_array( $raw ) ? $raw : []; /** @var array $raw */ @@ -98,7 +98,7 @@ public static function faqs(): array { return $cache; } - $raw = require OPENTRUST_PLUGIN_DIR . 'includes/data/faq-catalog.php'; + $raw = require ETTIC_OTC_PLUGIN_DIR . 'includes/data/faq-catalog.php'; $raw = is_array( $raw ) ? $raw : []; /** @@ -154,7 +154,7 @@ public static function seed_default_faqs(): void { $post_id = wp_insert_post( [ - 'post_type' => OpenTrust_CPT::FAQ, + 'post_type' => Ettic_OTC_CPT::FAQ, 'post_status' => 'publish', 'post_title' => $entry['question'], 'post_content' => $content, @@ -181,9 +181,9 @@ public static function seed_default_faqs(): void { */ public static function for_js( string $post_type ): array { $catalog = match ( $post_type ) { - OpenTrust_CPT::SUBPROCESSOR => self::subprocessors(), - OpenTrust_CPT::DATA_PRACTICE => self::data_practices(), - OpenTrust_CPT::CERTIFICATION => self::certifications(), + Ettic_OTC_CPT::SUBPROCESSOR => self::subprocessors(), + Ettic_OTC_CPT::DATA_PRACTICE => self::data_practices(), + Ettic_OTC_CPT::CERTIFICATION => self::certifications(), default => [], }; diff --git a/includes/class-opentrust-chat-budget.php b/includes/class-ettic-otc-chat-budget.php similarity index 98% rename from includes/class-opentrust-chat-budget.php rename to includes/class-ettic-otc-chat-budget.php index bd03b5f..c48be36 100644 --- a/includes/class-opentrust-chat-budget.php +++ b/includes/class-ettic-otc-chat-budget.php @@ -26,7 +26,7 @@ exit; } -final class OpenTrust_Chat_Budget { +final class Ettic_OTC_Chat_Budget { /** * Default per-day token cap when the operator hasn't set one. @@ -69,7 +69,7 @@ public static function check_and_reserve(int $tokens): bool { $tokens = 1; } - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); $daily_cap = (int) ($settings['ai_daily_token_budget'] ?? self::DEFAULT_DAILY_TOKEN_BUDGET); $monthly_cap = (int) ($settings['ai_monthly_token_budget'] ?? self::DEFAULT_MONTHLY_TOKEN_BUDGET); @@ -159,7 +159,7 @@ public static function daily_reset_at(): int { * Returns ['ok' => true] or ['ok' => false, 'retry_after' => seconds]. */ public static function check_ip_rate_limit(string $ip_hash): array { - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); $limit = (int) ($settings['ai_rate_limit_per_ip'] ?? self::DEFAULT_RATE_LIMIT_PER_IP); return self::check_sliding_window( 'opentrust_chat_rl_ip_' . $ip_hash, @@ -172,7 +172,7 @@ public static function check_ip_rate_limit(string $ip_hash): array { * Check + record a rate-limit hit for the given session hash. */ public static function check_session_rate_limit(string $session_hash): array { - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); $limit = (int) ($settings['ai_rate_limit_per_session'] ?? self::DEFAULT_RATE_LIMIT_PER_SESSION); return self::check_sliding_window( 'opentrust_chat_rl_session_' . $session_hash, @@ -276,7 +276,7 @@ public static function verify_turnstile_token(string $token, string $secret, str * and persisted in opentrust_settings on first use. */ public static function site_salt(): string { - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); $salt = (string) ($settings['opentrust_site_salt'] ?? ''); if ($salt === '') { $salt = wp_generate_password(64, true, true); diff --git a/includes/class-opentrust-chat-corpus.php b/includes/class-ettic-otc-chat-corpus.php similarity index 96% rename from includes/class-opentrust-chat-corpus.php rename to includes/class-ettic-otc-chat-corpus.php index 42db65f..e4f9a49 100644 --- a/includes/class-opentrust-chat-corpus.php +++ b/includes/class-ettic-otc-chat-corpus.php @@ -2,7 +2,7 @@ /** * Corpus builder for the agentic chat engine. * - * Turns published OpenTrust CPT content into two parallel projections: + * Turns published Ettic_OTC CPT content into two parallel projections: * * - `documents` — full per-document records the AI fetches via the * `get_document(id)` tool. Long-form policies are truncated to a 30K-token @@ -19,7 +19,7 @@ * inverted BM25 index used by `search_documents(query)` is built once at * cache-build time and persisted alongside the corpus. * - * Reads only published posts via OpenTrust_Repository — the same read-side + * Reads only published posts via Ettic_OTC_Repository — the same read-side * surface Render uses, so any cached fetch hit there is shared here. */ @@ -29,7 +29,7 @@ exit; } -final class OpenTrust_Chat_Corpus { +final class Ettic_OTC_Chat_Corpus { public const TRANSIENT_KEY = 'opentrust_chat_corpus'; public const TTL = 12 * HOUR_IN_SECONDS; @@ -60,7 +60,7 @@ final class OpenTrust_Chat_Corpus { /** * Postmeta key that stores the AI-generated 2–3 sentence policy summary. - * Read here; written by OpenTrust_Chat_Summarizer. Defined in the corpus + * Read here; written by Ettic_OTC_Chat_Summarizer. Defined in the corpus * class so this file works whether the summarizer class is loaded or not. */ public const POLICY_SUMMARY_META = '_opentrust_policy_chat_summary'; @@ -136,8 +136,8 @@ public static function invalidate(): void { */ public static function build(?string $locale = null): array { $locale = self::normalize_locale($locale); - $settings = OpenTrust::get_settings(); - $repo = OpenTrust_Repository::instance(); + $settings = Ettic_OTC::get_settings(); + $repo = Ettic_OTC_Repository::instance(); $visible = $settings['sections_visible'] ?? []; $documents = []; @@ -185,7 +185,7 @@ public static function build(?string $locale = null): array { $urls[] = $doc['url']; } } - $base = home_url('/' . ($settings['endpoint_slug'] ?? OpenTrust::DEFAULT_ENDPOINT_SLUG) . '/'); + $base = home_url('/' . ($settings['endpoint_slug'] ?? Ettic_OTC::DEFAULT_ENDPOINT_SLUG) . '/'); $urls[] = $base; foreach (['ot-certifications', 'ot-policies', 'ot-subprocessors', 'ot-data-practices', 'ot-contact'] as $anchor) { $urls[] = $base . '#' . $anchor; @@ -200,7 +200,7 @@ public static function build(?string $locale = null): array { $index = self::project_index($documents); // Inverted index for `search_documents`. - $bm25 = OpenTrust_Chat_Search::build($documents); + $bm25 = Ettic_OTC_Chat_Search::build($documents); // Token estimate for the rendered index — fed into the budget reserver. $company = (string) ($settings['company_name'] ?? get_bloginfo('name')); @@ -493,10 +493,10 @@ private static function collapse_whitespace(string $s): string { // ────────────────────────────────────────────── private static function format_policy(\WP_Post $post, array $settings): array { - $endpoint = $settings['endpoint_slug'] ?? OpenTrust::DEFAULT_ENDPOINT_SLUG; + $endpoint = $settings['endpoint_slug'] ?? Ettic_OTC::DEFAULT_ENDPOINT_SLUG; $url = home_url('/' . $endpoint . '/policy/' . $post->post_name . '/'); - $category_labels = OpenTrust_Render::policy_category_labels(); + $category_labels = Ettic_OTC_Render::policy_category_labels(); $category = (string) (get_post_meta($post->ID, '_opentrust_policy_category', true) ?: 'other'); $category_label = $category_labels[$category] ?? $category; $effective = (string) get_post_meta($post->ID, '_opentrust_policy_effective_date', true); @@ -540,12 +540,12 @@ private static function format_policy(\WP_Post $post, array $settings): array { } private static function format_certification(array $cert, array $settings): array { - $endpoint = $settings['endpoint_slug'] ?? OpenTrust::DEFAULT_ENDPOINT_SLUG; + $endpoint = $settings['endpoint_slug'] ?? Ettic_OTC::DEFAULT_ENDPOINT_SLUG; $url = home_url('/' . $endpoint . '/#ot-certifications'); $status_labels = ($cert['type'] ?? 'certified') === 'compliant' - ? OpenTrust_Render::cert_aligned_status_labels() - : OpenTrust_Render::cert_status_labels(); + ? Ettic_OTC_Render::cert_aligned_status_labels() + : Ettic_OTC_Render::cert_status_labels(); $status_label = $status_labels[$cert['status']] ?? $cert['status']; $lines = [ @@ -591,7 +591,7 @@ private static function format_certification(array $cert, array $settings): arra } private static function format_subprocessor(array $sub, array $settings): array { - $endpoint = $settings['endpoint_slug'] ?? OpenTrust::DEFAULT_ENDPOINT_SLUG; + $endpoint = $settings['endpoint_slug'] ?? Ettic_OTC::DEFAULT_ENDPOINT_SLUG; $url = home_url('/' . $endpoint . '/#ot-subprocessors'); $lines = ['Name: ' . ($sub['name'] ?? '')]; @@ -627,10 +627,10 @@ private static function format_subprocessor(array $sub, array $settings): array } private static function format_data_practice(array $dp, array $settings): array { - $endpoint = $settings['endpoint_slug'] ?? OpenTrust::DEFAULT_ENDPOINT_SLUG; + $endpoint = $settings['endpoint_slug'] ?? Ettic_OTC::DEFAULT_ENDPOINT_SLUG; $url = home_url('/' . $endpoint . '/#ot-data-practices'); - $legal_labels = OpenTrust_Render::legal_basis_labels(); + $legal_labels = Ettic_OTC_Render::legal_basis_labels(); $lines = ['Category: ' . (string) ($dp['title'] ?? '')]; if (!empty($dp['data_items']) && is_array($dp['data_items'])) { @@ -753,7 +753,7 @@ private static function format_contact(array $settings): ?array { return null; } - $endpoint = $settings['endpoint_slug'] ?? OpenTrust::DEFAULT_ENDPOINT_SLUG; + $endpoint = $settings['endpoint_slug'] ?? Ettic_OTC::DEFAULT_ENDPOINT_SLUG; $url = home_url('/' . $endpoint . '/#ot-contact'); return [ diff --git a/includes/class-opentrust-chat-log.php b/includes/class-ettic-otc-chat-log.php similarity index 97% rename from includes/class-opentrust-chat-log.php rename to includes/class-ettic-otc-chat-log.php index 3e9514f..398d201 100644 --- a/includes/class-opentrust-chat-log.php +++ b/includes/class-ettic-otc-chat-log.php @@ -17,15 +17,15 @@ exit; } -final class OpenTrust_Chat_Log { +final class Ettic_OTC_Chat_Log { public const CRON_HOOK = 'opentrust_chat_log_purge'; /** - * Daily purge cutoff. Three i18n strings in OpenTrust_Admin + * Daily purge cutoff. Three i18n strings in Ettic_OTC_Admin * (the AI-tab logging-toggle label, the Questions-page intro, and the * "%d questions logged in the last 90 days" plural) hardcode "90" in * their copy — if you change this value, grep for "90 days" and - * "90-day" under includes/class-opentrust-admin.php and update those + * "90-day" under includes/class-ettic-otc-admin.php and update those * strings together (the translation .po files will need a re-run too). */ public const RETENTION_DAYS = 90; @@ -73,7 +73,7 @@ public static function create_table(): void { * Insert a log row. No-op if logging is disabled in settings. */ public static function record(array $args): void { - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); if (empty($settings['ai_logging_enabled'])) { return; } @@ -239,4 +239,4 @@ public static function unschedule_cron(): void { } // Wire the cron hook. -add_action(OpenTrust_Chat_Log::CRON_HOOK, [OpenTrust_Chat_Log::class, 'purge_old']); +add_action(Ettic_OTC_Chat_Log::CRON_HOOK, [Ettic_OTC_Chat_Log::class, 'purge_old']); diff --git a/includes/class-opentrust-chat-search.php b/includes/class-ettic-otc-chat-search.php similarity index 99% rename from includes/class-opentrust-chat-search.php rename to includes/class-ettic-otc-chat-search.php index 86a19a3..e5da1d7 100644 --- a/includes/class-opentrust-chat-search.php +++ b/includes/class-ettic-otc-chat-search.php @@ -26,7 +26,7 @@ exit; } -final class OpenTrust_Chat_Search { +final class Ettic_OTC_Chat_Search { /** * English stop-words. Trust-center content is overwhelmingly English even diff --git a/includes/class-opentrust-chat-secrets.php b/includes/class-ettic-otc-chat-secrets.php similarity index 99% rename from includes/class-opentrust-chat-secrets.php rename to includes/class-ettic-otc-chat-secrets.php index acb707a..056578a 100644 --- a/includes/class-opentrust-chat-secrets.php +++ b/includes/class-ettic-otc-chat-secrets.php @@ -18,7 +18,7 @@ exit; } -final class OpenTrust_Chat_Secrets { +final class Ettic_OTC_Chat_Secrets { private const SENTINEL = 'ot_enc_v1:'; diff --git a/includes/class-opentrust-chat-stream-collector.php b/includes/class-ettic-otc-chat-stream-collector.php similarity index 93% rename from includes/class-opentrust-chat-stream-collector.php rename to includes/class-ettic-otc-chat-stream-collector.php index 4c67ab0..045b2b4 100644 --- a/includes/class-opentrust-chat-stream-collector.php +++ b/includes/class-ettic-otc-chat-stream-collector.php @@ -4,8 +4,8 @@ * * Before this class existed, the citation URL-allowlist gate, doc-id de-dup, * usage accumulator, and tool-name capture lived as a hand-rolled `$on_chunk` - * closure repeated three times: in OpenTrust_Chat::drive_stream, ::drive_blocking, - * and OpenTrust_Render::handle_chat_noscript_post. The audit flagged this as + * closure repeated three times: in Ettic_OTC_Chat::drive_stream, ::drive_blocking, + * and Ettic_OTC_Render::handle_chat_noscript_post. The audit flagged this as * the highest-leverage drift hazard in the codebase: each closure was the * security boundary for which citations make it back to the visitor, and the * doc-id de-dup comment was already copy-pasted verbatim three times — exactly @@ -15,7 +15,7 @@ * to the allowlist, the de-dup key, or the refusal detector lands in one place. * * Usage: - * $collector = new OpenTrust_Chat_Stream_Collector($corpus['urls'] ?? []); + * $collector = new Ettic_OTC_Chat_Stream_Collector($corpus['urls'] ?? []); * $on_chunk = static function (array $event) use ($collector, $sse_emit) { * if ($collector->ingest($event)) { * $sse_emit($event); // forward to the client @@ -35,7 +35,7 @@ exit; } -final class OpenTrust_Chat_Stream_Collector { +final class Ettic_OTC_Chat_Stream_Collector { /** @var array */ private array $whitelist; @@ -84,7 +84,7 @@ public function ingest(array $event): bool { case 'citation': $url = (string) ($data['url'] ?? ''); - if (!OpenTrust_Chat::url_allowed($url, $this->whitelist)) { + if (!Ettic_OTC_Chat::url_allowed($url, $this->whitelist)) { return false; // dropped by allowlist } // De-dup by DOCUMENT ID (each corpus doc has a unique id like @@ -133,7 +133,7 @@ public function ingest(array $event): bool { * Two-signal refusal heuristic: canonical phrase + zero citations. */ public function detect_refusal(): bool { - return OpenTrust_Chat::detect_refusal($this->answer, $this->citations); + return Ettic_OTC_Chat::detect_refusal($this->answer, $this->citations); } /** @@ -155,7 +155,7 @@ public function stats(): array { 'citation_count' => count($this->citations), 'refused' => $this->detect_refusal(), 'tool_turns' => count($this->tool_names), - 'tool_names' => OpenTrust_Chat::format_tool_names_for_log($this->tool_names), + 'tool_names' => Ettic_OTC_Chat::format_tool_names_for_log($this->tool_names), ]; } } diff --git a/includes/class-opentrust-chat-summarizer.php b/includes/class-ettic-otc-chat-summarizer.php similarity index 93% rename from includes/class-opentrust-chat-summarizer.php rename to includes/class-ettic-otc-chat-summarizer.php index 0c5daf1..da5c05b 100644 --- a/includes/class-opentrust-chat-summarizer.php +++ b/includes/class-ettic-otc-chat-summarizer.php @@ -32,10 +32,10 @@ exit; } -final class OpenTrust_Chat_Summarizer { +final class Ettic_OTC_Chat_Summarizer { /** - * Postmeta key. Mirror of OpenTrust_Chat_Corpus::POLICY_SUMMARY_META — + * Postmeta key. Mirror of Ettic_OTC_Chat_Corpus::POLICY_SUMMARY_META — * declared in both classes so neither file requires the other to load. */ public const META_KEY = '_opentrust_policy_chat_summary'; @@ -55,14 +55,14 @@ final class OpenTrust_Chat_Summarizer { private const POLICY_INPUT_MAX_CHARS = 12_000; public static function bootstrap(): void { - add_action('save_post_' . OpenTrust_CPT::POLICY, [self::class, 'on_save_post'], 20, 3); + add_action('save_post_' . Ettic_OTC_CPT::POLICY, [self::class, 'on_save_post'], 20, 3); add_action(self::CRON_HOOK, [self::class, 'generate']); } /** * Hook handler. Decides whether a summary regeneration is warranted and * schedules a debounced cron call when it is. Skip conditions mirror the - * fallback ladder in OpenTrust_Chat_Corpus::policy_summary(). + * fallback ladder in Ettic_OTC_Chat_Corpus::policy_summary(). */ public static function on_save_post(int $post_id, \WP_Post $post, bool $update): void { if ($post->post_status !== 'publish') { @@ -71,7 +71,7 @@ public static function on_save_post(int $post_id, \WP_Post $post, bool $update): if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) { return; } - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); if (empty($settings['ai_auto_summarize'])) { return; } @@ -105,13 +105,13 @@ public static function on_save_post(int $post_id, \WP_Post $post, bool $update): */ public static function generate(int $post_id): void { $post = get_post($post_id); - if (!$post instanceof \WP_Post || $post->post_type !== OpenTrust_CPT::POLICY || $post->post_status !== 'publish') { + if (!$post instanceof \WP_Post || $post->post_type !== Ettic_OTC_CPT::POLICY || $post->post_status !== 'publish') { return; } // Re-check skip conditions at run-time. Settings may have changed // between scheduling and execution. - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); if (empty($settings['ai_auto_summarize'])) { return; } @@ -125,12 +125,12 @@ public static function generate(int $post_id): void { return; } - $adapter = OpenTrust_Chat_Provider::for($provider_slug); + $adapter = Ettic_OTC_Chat_Provider::for($provider_slug); if (!$adapter) { self::log_failure($post_id, 'unknown provider: ' . $provider_slug); return; } - $api_key = OpenTrust_Chat_Secrets::get($provider_slug); + $api_key = Ettic_OTC_Chat_Secrets::get($provider_slug); if ($api_key === null || $api_key === '') { self::log_failure($post_id, 'no API key on file for ' . $provider_slug); return; @@ -201,8 +201,8 @@ public static function generate(int $post_id): void { // Force the next chat request to rebuild the corpus index with the // fresh summary. - if (class_exists('OpenTrust_Chat_Corpus')) { - OpenTrust_Chat_Corpus::invalidate(); + if (class_exists('Ettic_OTC_Chat_Corpus')) { + Ettic_OTC_Chat_Corpus::invalidate(); } } @@ -212,7 +212,7 @@ public static function generate(int $post_id): void { */ public static function sweep_all(): int { $posts = get_posts([ - 'post_type' => OpenTrust_CPT::POLICY, + 'post_type' => Ettic_OTC_CPT::POLICY, 'posts_per_page' => -1, 'post_status' => 'publish', 'fields' => 'ids', @@ -252,7 +252,7 @@ public static function sweep_all(): int { */ public static function missing_summary_count(): int { $posts = get_posts([ - 'post_type' => OpenTrust_CPT::POLICY, + 'post_type' => Ettic_OTC_CPT::POLICY, 'posts_per_page' => -1, 'post_status' => 'publish', 'fields' => 'ids', @@ -317,6 +317,6 @@ private static function clean_summary(string $raw): string { } private static function log_failure(int $post_id, string $reason): void { - OpenTrust::debug_log(sprintf('policy summary generation failed for post %d: %s', $post_id, $reason)); + Ettic_OTC::debug_log(sprintf('policy summary generation failed for post %d: %s', $post_id, $reason)); } } diff --git a/includes/class-opentrust-chat.php b/includes/class-ettic-otc-chat.php similarity index 94% rename from includes/class-opentrust-chat.php rename to includes/class-ettic-otc-chat.php index d85867f..e197ce5 100644 --- a/includes/class-opentrust-chat.php +++ b/includes/class-ettic-otc-chat.php @@ -19,7 +19,7 @@ exit; } -final class OpenTrust_Chat { +final class Ettic_OTC_Chat { public const REST_NAMESPACE = 'opentrust/v1'; public const REST_ROUTE = '/chat'; @@ -35,7 +35,7 @@ final class OpenTrust_Chat { /** * Default character cap on a single visitor message. Operators can override * via the ai_max_message_length setting (clamped to 100..4000 in - * OpenTrust_Admin::sanitize_settings). + * Ettic_OTC_Admin::sanitize_settings). */ public const DEFAULT_MAX_MESSAGE_LENGTH = 1000; @@ -63,17 +63,17 @@ private function __construct() { // saves, deletes, trash/untrash, and publish transitions all flush // through a single canonical CPT list (CORPUS = the four indexed CPTs; // FAQs are deliberately not in the chat corpus). - OpenTrust_CPT::register_invalidator( - OpenTrust_CPT::CORPUS, - [OpenTrust_Chat_Corpus::class, 'invalidate'] + Ettic_OTC_CPT::register_invalidator( + Ettic_OTC_CPT::CORPUS, + [Ettic_OTC_Chat_Corpus::class, 'invalidate'] ); - add_action('update_option_opentrust_settings', [OpenTrust_Chat_Corpus::class, 'invalidate']); + add_action('update_option_opentrust_settings', [Ettic_OTC_Chat_Corpus::class, 'invalidate']); // Auto-summarize hooks. Independent of corpus invalidation — the // summarizer schedules a debounced cron call rather than running // inline on save_post, so it doesn't block the editor. - if (class_exists('OpenTrust_Chat_Summarizer')) { - OpenTrust_Chat_Summarizer::bootstrap(); + if (class_exists('Ettic_OTC_Chat_Summarizer')) { + Ettic_OTC_Chat_Summarizer::bootstrap(); } } @@ -114,21 +114,21 @@ public function permission_callback(WP_REST_Request $request): bool|WP_Error { ); } - $settings = OpenTrust::get_settings(); - $ip_hash = OpenTrust_Chat_Budget::hash_ip(OpenTrust_Chat_Budget::visitor_ip()); - $session_tok = OpenTrust_Chat_Budget::session_token(); - $session_hash = OpenTrust_Chat_Budget::hash_session($session_tok); + $settings = Ettic_OTC::get_settings(); + $ip_hash = Ettic_OTC_Chat_Budget::hash_ip(Ettic_OTC_Chat_Budget::visitor_ip()); + $session_tok = Ettic_OTC_Chat_Budget::session_token(); + $session_hash = Ettic_OTC_Chat_Budget::hash_session($session_tok); // Gate 2: Turnstile (if enabled and session not yet verified). - if (OpenTrust_Chat_Budget::turnstile_required($settings)) { - if (!OpenTrust_Chat_Budget::turnstile_session_verified($session_hash)) { + if (Ettic_OTC_Chat_Budget::turnstile_required($settings)) { + if (!Ettic_OTC_Chat_Budget::turnstile_session_verified($session_hash)) { // The secret is stored as a libsodium ciphertext blob in // opentrust_settings; decrypt at the edge — if decryption // fails we fail closed and surface the challenge error. $stored_secret = (string) ($settings['turnstile_secret_key'] ?? ''); - $secret = OpenTrust_Chat_Secrets::decrypt($stored_secret) ?? ''; + $secret = Ettic_OTC_Chat_Secrets::decrypt($stored_secret) ?? ''; $token = (string) $request->get_param('turnstile_token'); - $ok = $secret !== '' && OpenTrust_Chat_Budget::verify_turnstile_token( + $ok = $secret !== '' && Ettic_OTC_Chat_Budget::verify_turnstile_token( $token, $secret, $session_hash, @@ -145,7 +145,7 @@ public function permission_callback(WP_REST_Request $request): bool|WP_Error { } // Gate 3a: per-IP rate limit. - $ip_check = OpenTrust_Chat_Budget::check_ip_rate_limit($ip_hash); + $ip_check = Ettic_OTC_Chat_Budget::check_ip_rate_limit($ip_hash); if (empty($ip_check['ok'])) { return new WP_Error( 'ai_rate_limited_ip', @@ -156,7 +156,7 @@ public function permission_callback(WP_REST_Request $request): bool|WP_Error { // Gate 3b: per-session rate limit. if ($session_hash !== '') { - $sess_check = OpenTrust_Chat_Budget::check_session_rate_limit($session_hash); + $sess_check = Ettic_OTC_Chat_Budget::check_session_rate_limit($session_hash); if (empty($sess_check['ok'])) { return new WP_Error( 'ai_rate_limited_session', @@ -174,7 +174,7 @@ public function permission_callback(WP_REST_Request $request): bool|WP_Error { // ────────────────────────────────────────────── public function handle_chat(WP_REST_Request $request) { - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); // Gate 1: feature configured? if (empty($settings['ai_enabled']) || empty($settings['ai_provider']) || empty($settings['ai_model'])) { @@ -185,7 +185,7 @@ public function handle_chat(WP_REST_Request $request) { ); } - $adapter = OpenTrust_Chat_Provider::for((string) $settings['ai_provider']); + $adapter = Ettic_OTC_Chat_Provider::for((string) $settings['ai_provider']); if (!$adapter) { return new WP_Error( 'ai_bad_provider', @@ -194,7 +194,7 @@ public function handle_chat(WP_REST_Request $request) { ); } - $api_key = OpenTrust_Chat_Secrets::get((string) $settings['ai_provider']); + $api_key = Ettic_OTC_Chat_Secrets::get((string) $settings['ai_provider']); if ($api_key === null) { return new WP_Error( 'ai_no_key', @@ -222,17 +222,17 @@ public function handle_chat(WP_REST_Request $request) { // prompt and whatever it pulls in via tool calls. Per-document // truncation lives inside the corpus formatter. $locale = (string) determine_locale(); - $corpus = OpenTrust_Chat_Corpus::get_or_build($locale); + $corpus = Ettic_OTC_Chat_Corpus::get_or_build($locale); // Reserve against the token budget BEFORE the upstream call. $estimated = $this->estimate_request_tokens($messages, $corpus); - if (!OpenTrust_Chat_Budget::check_and_reserve($estimated)) { + if (!Ettic_OTC_Chat_Budget::check_and_reserve($estimated)) { return new WP_Error( 'budget_exhausted', __('The daily chat budget for this site has been reached. Please try again later.', 'opentrust'), [ 'status' => 503, - 'reset_at' => gmdate('c', OpenTrust_Chat_Budget::daily_reset_at()), + 'reset_at' => gmdate('c', Ettic_OTC_Chat_Budget::daily_reset_at()), ] ); } @@ -259,8 +259,8 @@ public function handle_chat(WP_REST_Request $request) { break; } } - $ip_hash = OpenTrust_Chat_Budget::hash_ip(OpenTrust_Chat_Budget::visitor_ip()); - $session_hash = OpenTrust_Chat_Budget::hash_session(OpenTrust_Chat_Budget::session_token()); + $ip_hash = Ettic_OTC_Chat_Budget::hash_ip(Ettic_OTC_Chat_Budget::visitor_ip()); + $session_hash = Ettic_OTC_Chat_Budget::hash_session(Ettic_OTC_Chat_Budget::session_token()); $start_ms = (int) (microtime(true) * 1000); $log_row = [ @@ -277,8 +277,8 @@ public function handle_chat(WP_REST_Request $request) { if ($wants_sse) { $this->setup_sse_response(); $result = $this->drive_stream($adapter, $args); - OpenTrust_Chat_Budget::commit($estimated, $result['actual_tokens']); - OpenTrust_Chat_Log::record(array_merge($log_row, [ + Ettic_OTC_Chat_Budget::commit($estimated, $result['actual_tokens']); + Ettic_OTC_Chat_Log::record(array_merge($log_row, [ 'tokens_in' => $result['tokens_in'], 'tokens_out' => $result['tokens_out'], 'citation_count' => $result['citation_count'], @@ -291,8 +291,8 @@ public function handle_chat(WP_REST_Request $request) { } $response = $this->drive_blocking($adapter, $args, $blocking_stats); - OpenTrust_Chat_Budget::commit($estimated, (int) ($blocking_stats['actual_tokens'] ?? 0)); - OpenTrust_Chat_Log::record(array_merge($log_row, [ + Ettic_OTC_Chat_Budget::commit($estimated, (int) ($blocking_stats['actual_tokens'] ?? 0)); + Ettic_OTC_Chat_Log::record(array_merge($log_row, [ 'tokens_in' => (int) ($blocking_stats['tokens_in'] ?? 0), 'tokens_out' => (int) ($blocking_stats['tokens_out'] ?? 0), 'citation_count' => (int) ($blocking_stats['citation_count'] ?? 0), @@ -303,7 +303,7 @@ public function handle_chat(WP_REST_Request $request) { ])); return $response; } catch (\Throwable $e) { - OpenTrust_Chat_Budget::release($estimated); + Ettic_OTC_Chat_Budget::release($estimated); throw $e; } } @@ -368,7 +368,7 @@ private function setup_sse_response(): void { * Run the provider in streaming mode. Emits SSE events directly to the * client. Returns usage stats for budget commit + log row. The collector * owns the citation allowlist, doc-id de-dup, usage accounting, refusal - * detection, and tool-name capture — see OpenTrust_Chat_Stream_Collector. + * detection, and tool-name capture — see Ettic_OTC_Chat_Stream_Collector. * * @return array{ * actual_tokens:int, tokens_in:int, tokens_out:int, @@ -376,7 +376,7 @@ private function setup_sse_response(): void { * refused:bool, tool_turns:int, tool_names:string * } */ - private function drive_stream(OpenTrust_Chat_Provider $adapter, array $args): array { + private function drive_stream(Ettic_OTC_Chat_Provider $adapter, array $args): array { $collector = $this->build_collector($args); $on_chunk = static function (array $event) use ($collector): void { @@ -421,7 +421,7 @@ private function drive_stream(OpenTrust_Chat_Provider $adapter, array $args): ar * Used when the client cannot accept SSE (JS disabled). Same collector * as drive_stream — only the post-loop wrap-up differs. */ - private function drive_blocking(OpenTrust_Chat_Provider $adapter, array $args, ?array &$stats = null): WP_REST_Response|WP_Error { + private function drive_blocking(Ettic_OTC_Chat_Provider $adapter, array $args, ?array &$stats = null): WP_REST_Response|WP_Error { $collector = $this->build_collector($args); $on_chunk = static function (array $event) use ($collector): void { @@ -452,10 +452,10 @@ private function drive_blocking(OpenTrust_Chat_Provider $adapter, array $args, ? * Build a fresh collector seeded with the corpus URL allowlist. Pulled * out so both drive_* paths can't drift on which URLs they accept. */ - private function build_collector(array $args): OpenTrust_Chat_Stream_Collector { + private function build_collector(array $args): Ettic_OTC_Chat_Stream_Collector { $corpus = is_array($args['corpus'] ?? null) ? $args['corpus'] : []; $urls = is_array($corpus['urls'] ?? null) ? $corpus['urls'] : []; - return new OpenTrust_Chat_Stream_Collector($urls); + return new Ettic_OTC_Chat_Stream_Collector($urls); } /** @@ -466,7 +466,7 @@ private function build_collector(array $args): OpenTrust_Chat_Stream_Collector { * is engaged is the same in both paths. */ private function run_chat( - OpenTrust_Chat_Provider $adapter, + Ettic_OTC_Chat_Provider $adapter, array $args, callable $on_chunk ): ?\Throwable { @@ -578,14 +578,14 @@ public static function detect_refusal(string $answer, array $citations): bool { * baseline role + behavior rules, the corpus index (table of contents), * and the retrieval-grounding rules specific to the agentic engine. * - * Public + static so the noscript chat path in OpenTrust_Render can use + * Public + static so the noscript chat path in Ettic_OTC_Render can use * the same prompt as the streaming path — they're functionally identical. */ public static function build_system_prompt(array $settings, array $corpus): string { $company = (string) ($settings['company_name'] ?? get_bloginfo('name')); $contact = (string) ($settings['ai_contact_url'] ?? ''); if ($contact === '') { - $contact = home_url('/' . ($settings['endpoint_slug'] ?? OpenTrust::DEFAULT_ENDPOINT_SLUG) . '/'); + $contact = home_url('/' . ($settings['endpoint_slug'] ?? Ettic_OTC::DEFAULT_ENDPOINT_SLUG) . '/'); } $lines = []; @@ -616,7 +616,7 @@ public static function build_system_prompt(array $settings, array $corpus): stri $index = is_array($corpus['index'] ?? null) ? $corpus['index'] : []; if (!empty($index)) { $lines[] = ''; - $lines[] = OpenTrust_Chat_Corpus::format_index_for_prompt($index, $company); + $lines[] = Ettic_OTC_Chat_Corpus::format_index_for_prompt($index, $company); } return implode("\n", $lines); @@ -751,7 +751,7 @@ public static function resolve_tool(string $name, array $args, array $corpus, ar if ($bm25 === null) { return [self::error_search_result(__('Search index unavailable.', 'opentrust'))]; } - $hits = OpenTrust_Chat_Search::search($bm25, $query, $limit); + $hits = Ettic_OTC_Chat_Search::search($bm25, $query, $limit); if (empty($hits)) { return [self::error_search_result(sprintf( /* translators: %s is the search query. */ diff --git a/includes/class-opentrust-cpt.php b/includes/class-ettic-otc-cpt.php similarity index 99% rename from includes/class-opentrust-cpt.php rename to includes/class-ettic-otc-cpt.php index 89622d3..13a631e 100644 --- a/includes/class-opentrust-cpt.php +++ b/includes/class-ettic-otc-cpt.php @@ -9,7 +9,7 @@ exit; } -final class OpenTrust_CPT { +final class Ettic_OTC_CPT { /** * CPT slug constants. Use these everywhere instead of bare strings so a @@ -26,7 +26,7 @@ final class OpenTrust_CPT { * import/export back-compat remap. Do not introduce new references. * * @deprecated 1.1.0 Drop in 2.0.0 once v1.0.x upgrades are no longer supported. - * The major-version mismatch check in OpenTrust_IO::validate_manifest() + * The major-version mismatch check in Ettic_OTC_IO::validate_manifest() * already hard-rejects 1.x archives on a 2.x destination, so the * import remap becomes redundant at the same cutoff. */ @@ -49,7 +49,7 @@ final class OpenTrust_CPT { * Legacy postmeta keys from v1.0–v1.1, mapped old `_ot_*` → new * `_opentrust_*`. Retained for import back-compat: legacy archives * (exported by v1.0.x/v1.1.x) still carry these keys, and the importer - * remaps them on read via OpenTrust_IO::remap_legacy_meta_keys(). + * remaps them on read via Ettic_OTC_IO::remap_legacy_meta_keys(). * Phase 8 extends the chain through `_ettic_otc_*`. */ public const LEGACY_META_MAP = [ @@ -107,7 +107,7 @@ final class OpenTrust_CPT { ]; /** - * Every OpenTrust CPT slug, in the order they appear in the trust center + * Every Ettic_OTC CPT slug, in the order they appear in the trust center * page. Drives the render cache invalidator and the admin submenu fixer. */ public const ALL = [ @@ -541,7 +541,7 @@ public function render_policy_meta_box(\WP_Post $post): void { $attachment_url = $attachment_id ? wp_get_attachment_url($attachment_id) : ''; $attachment_name = $attachment_id ? get_the_title($attachment_id) : ''; - $categories = OpenTrust_Render::policy_category_labels(); + $categories = Ettic_OTC_Render::policy_category_labels(); ?>

@@ -707,7 +707,7 @@ public function render_dp_meta_box(\WP_Post $post): void { $prop_sold = (bool) get_post_meta($post->ID, '_opentrust_dp_sold', true); $prop_encrypted = (bool) get_post_meta($post->ID, '_opentrust_dp_encrypted', true); - $basis_options = OpenTrust_Render::legal_basis_labels(); + $basis_options = Ettic_OTC_Render::legal_basis_labels(); ?> @@ -878,12 +878,12 @@ private function save_policy_meta(int $post_id): void { $post = get_post($post_id); if ($post && 'publish' === $post->post_status) { $summary = sanitize_text_field( wp_unslash( $_POST['opentrust_version_summary'] ?? '' ) ); - OpenTrust_Version::bump_version($post_id, $summary); + Ettic_OTC_Version::bump_version($post_id, $summary); } } // Ensure first-publish posts get v1. - OpenTrust_Version::ensure_initial_version($post_id); + Ettic_OTC_Version::ensure_initial_version($post_id); $ref_id = sanitize_text_field( wp_unslash( $_POST['opentrust_policy_ref_id'] ?? '' ) ); // Collapse internal whitespace runs so "POL 012" becomes "POL 012" on save. @@ -1032,8 +1032,8 @@ public function cert_column_content(string $column, int $post_id): void { $status = get_post_meta($post_id, '_opentrust_cert_status', true) ?: 'active'; $type = get_post_meta($post_id, '_opentrust_cert_type', true) ?: 'compliant'; $labels = $type === 'compliant' - ? OpenTrust_Render::cert_aligned_status_labels() - : OpenTrust_Render::cert_status_labels(); + ? Ettic_OTC_Render::cert_aligned_status_labels() + : Ettic_OTC_Render::cert_status_labels(); $swatch = match ($status) { 'active' => 'background:#dcfce7;color:#166534', 'in_progress' => 'background:#fef9c3;color:#854d0e', @@ -1076,7 +1076,7 @@ public function policy_column_content(string $column, int $post_id): void { } printf('%s', esc_html($ref)); })(), - 'opentrust_category' => print(esc_html(OpenTrust_Render::policy_category_labels()[get_post_meta($post_id, '_opentrust_policy_category', true) ?: 'other'] ?? '')), + 'opentrust_category' => print(esc_html(Ettic_OTC_Render::policy_category_labels()[get_post_meta($post_id, '_opentrust_policy_category', true) ?: 'other'] ?? '')), 'opentrust_version' => printf('v%s', esc_html((string) ((int) get_post_meta($post_id, '_opentrust_version', true) ?: 1))), 'opentrust_pdf' => print(((int) get_post_meta($post_id, '_opentrust_policy_attachment_id', true)) > 0 ? '' : ''), default => null, diff --git a/includes/class-opentrust-io.php b/includes/class-ettic-otc-io.php similarity index 94% rename from includes/class-opentrust-io.php rename to includes/class-ettic-otc-io.php index bf1331d..c650245 100644 --- a/includes/class-opentrust-io.php +++ b/includes/class-ettic-otc-io.php @@ -9,7 +9,7 @@ exit; } -final class OpenTrust_IO { +final class Ettic_OTC_IO { public const SCHEMA_VERSION = 1; public const FORMAT_SETTINGS = 'opentrust-settings'; @@ -35,9 +35,9 @@ final class OpenTrust_IO { 'ai_model_recommended', ]; - // Keep in sync with class-opentrust-cpt.php save handlers. + // Keep in sync with class-ettic-otc-cpt.php save handlers. private const META_KEYS = [ - OpenTrust_CPT::POLICY => [ + Ettic_OTC_CPT::POLICY => [ '_opentrust_uuid', '_opentrust_policy_ref_id', '_opentrust_policy_category', @@ -52,7 +52,7 @@ final class OpenTrust_IO { '_opentrust_policy_chat_summary_updated_at', '_opentrust_policy_chat_summary_origin', ], - OpenTrust_CPT::CERTIFICATION => [ + Ettic_OTC_CPT::CERTIFICATION => [ '_opentrust_uuid', '_opentrust_cert_type', '_opentrust_cert_status', @@ -63,7 +63,7 @@ final class OpenTrust_IO { '_opentrust_cert_artifact_id', '_opentrust_cert_description', ], - OpenTrust_CPT::SUBPROCESSOR => [ + Ettic_OTC_CPT::SUBPROCESSOR => [ '_opentrust_uuid', '_opentrust_sub_purpose', '_opentrust_sub_data_processed', @@ -71,7 +71,7 @@ final class OpenTrust_IO { '_opentrust_sub_website', '_opentrust_sub_dpa_signed', ], - OpenTrust_CPT::DATA_PRACTICE => [ + Ettic_OTC_CPT::DATA_PRACTICE => [ '_opentrust_uuid', '_opentrust_dp_data_items', '_opentrust_dp_purpose', @@ -85,7 +85,7 @@ final class OpenTrust_IO { '_opentrust_dp_sold', '_opentrust_dp_encrypted', ], - OpenTrust_CPT::FAQ => [ + Ettic_OTC_CPT::FAQ => [ '_opentrust_uuid', '_opentrust_faq_related_policy', ], @@ -93,17 +93,17 @@ final class OpenTrust_IO { // Meta keys whose value is an attachment ID; serialized as __media_ref. private const ATTACHMENT_META_KEYS = [ - OpenTrust_CPT::POLICY => ['_opentrust_policy_attachment_id'], - OpenTrust_CPT::CERTIFICATION => ['_opentrust_cert_badge_id', '_opentrust_cert_artifact_id'], - OpenTrust_CPT::SUBPROCESSOR => [], - OpenTrust_CPT::DATA_PRACTICE => [], - OpenTrust_CPT::FAQ => [], + Ettic_OTC_CPT::POLICY => ['_opentrust_policy_attachment_id'], + Ettic_OTC_CPT::CERTIFICATION => ['_opentrust_cert_badge_id', '_opentrust_cert_artifact_id'], + Ettic_OTC_CPT::SUBPROCESSOR => [], + Ettic_OTC_CPT::DATA_PRACTICE => [], + Ettic_OTC_CPT::FAQ => [], ]; // meta_key => target_cpt_slug. Cross-CPT refs serialized as __post_ref. private const POST_REF_META_KEYS = [ - OpenTrust_CPT::FAQ => [ - '_opentrust_faq_related_policy' => OpenTrust_CPT::POLICY, + Ettic_OTC_CPT::FAQ => [ + '_opentrust_faq_related_policy' => Ettic_OTC_CPT::POLICY, ], ]; @@ -114,7 +114,7 @@ final class OpenTrust_IO { // ────────────────────────────────────────────── public static function build_settings_manifest(bool $include_media = true): array { - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); foreach (self::SETTINGS_EXCLUDE as $k) { unset($settings[$k]); } @@ -133,8 +133,8 @@ public static function build_settings_manifest(bool $include_media = true): arra return [ 'format' => self::FORMAT_SETTINGS, 'schema' => self::SCHEMA_VERSION, - 'opentrust_version' => OPENTRUST_VERSION, - 'db_version' => OPENTRUST_DB_VERSION, + 'opentrust_version' => ETTIC_OTC_VERSION, + 'db_version' => ETTIC_OTC_DB_VERSION, 'exported_at' => gmdate('c'), 'site_url' => home_url('/'), 'site_locale' => get_locale(), @@ -177,8 +177,8 @@ public static function build_content_manifest(array $selection, bool $include_me return [ 'format' => self::FORMAT_CONTENT, 'schema' => self::SCHEMA_VERSION, - 'opentrust_version' => OPENTRUST_VERSION, - 'db_version' => OPENTRUST_DB_VERSION, + 'opentrust_version' => ETTIC_OTC_VERSION, + 'db_version' => ETTIC_OTC_DB_VERSION, 'exported_at' => gmdate('c'), 'site_url' => home_url('/'), 'site_locale' => get_locale(), @@ -250,13 +250,13 @@ public static function validate_manifest(array $manifest): array { } $their_major = (int) explode('.', (string) ($manifest['opentrust_version'] ?? '0.0.0'))[0]; - $our_major = (int) explode('.', OPENTRUST_VERSION)[0]; + $our_major = (int) explode('.', ETTIC_OTC_VERSION)[0]; if ($their_major !== $our_major) { $errors[] = sprintf( /* translators: %1$s: their version, %2$s: our version */ __('Plugin major version mismatch (export: %1$s, this site: %2$s).', 'opentrust'), (string) ($manifest['opentrust_version'] ?? '?'), - OPENTRUST_VERSION + ETTIC_OTC_VERSION ); } @@ -313,12 +313,12 @@ public static function apply_content_import(array $manifest, string $zip_path, s // Suppress the chat summarizer for the duration of the import, otherwise // every imported policy queues a fresh summary generation (real cost). - $had_summarizer = remove_action('save_post_' . OpenTrust_CPT::POLICY, ['OpenTrust_Chat_Summarizer', 'on_save_post'], 20); + $had_summarizer = remove_action('save_post_' . Ettic_OTC_CPT::POLICY, ['Ettic_OTC_Chat_Summarizer', 'on_save_post'], 20); $media_map = self::sideload_bundled_media($manifest['media'] ?? [], $zip_path, $errors); // Policies first so FAQs can resolve their policy refs in one pass. - $cpt_order = [OpenTrust_CPT::POLICY, OpenTrust_CPT::CERTIFICATION, OpenTrust_CPT::SUBPROCESSOR, OpenTrust_CPT::DATA_PRACTICE, OpenTrust_CPT::FAQ]; + $cpt_order = [Ettic_OTC_CPT::POLICY, Ettic_OTC_CPT::CERTIFICATION, Ettic_OTC_CPT::SUBPROCESSOR, Ettic_OTC_CPT::DATA_PRACTICE, Ettic_OTC_CPT::FAQ]; $uuid_to_new_id = []; foreach ($cpt_order as $cpt) { @@ -343,10 +343,10 @@ public static function apply_content_import(array $manifest, string $zip_path, s self::remap_post_references($manifest['records'] ?? [], $uuid_to_new_id); if ($had_summarizer) { - add_action('save_post_' . OpenTrust_CPT::POLICY, ['OpenTrust_Chat_Summarizer', 'on_save_post'], 20, 3); + add_action('save_post_' . Ettic_OTC_CPT::POLICY, ['Ettic_OTC_Chat_Summarizer', 'on_save_post'], 20, 3); } - OpenTrust::instance()->invalidate_cache(); + Ettic_OTC::instance()->invalidate_cache(); return compact('created', 'updated', 'skipped', 'errors'); } @@ -368,7 +368,7 @@ public static function apply_settings_import(array $manifest, string $zip_path): } } - $current = OpenTrust::get_settings(); + $current = Ettic_OTC::get_settings(); $merged = array_merge($current, $imported); foreach (self::SETTINGS_EXCLUDE as $k) { @@ -382,7 +382,7 @@ public static function apply_settings_import(array $manifest, string $zip_path): set_transient('opentrust_flush_rewrite', true); } - OpenTrust::instance()->invalidate_cache(); + Ettic_OTC::instance()->invalidate_cache(); return ['updated' => count($imported), 'errors' => $errors]; } @@ -433,7 +433,7 @@ private static function remap_legacy_cpt_keys(array $manifest): array { } $out = []; foreach ($manifest['records'] as $cpt => $recs) { - $out[OpenTrust_CPT::LEGACY_MAP[$cpt] ?? $cpt] = $recs; + $out[Ettic_OTC_CPT::LEGACY_MAP[$cpt] ?? $cpt] = $recs; } $manifest['records'] = $out; return $manifest; @@ -446,13 +446,13 @@ private static function remap_legacy_cpt_keys(array $manifest): array { * old key names and read back as empty. * * @deprecated 1.1.1 Drop in 2.0.0 alongside remap_legacy_cpt_keys() and - * OpenTrust_CPT::LEGACY_META_MAP. + * Ettic_OTC_CPT::LEGACY_META_MAP. */ private static function remap_legacy_meta_keys(array $manifest): array { if (empty($manifest['records']) || !is_array($manifest['records'])) { return $manifest; } - $map = OpenTrust_CPT::LEGACY_META_MAP; + $map = Ettic_OTC_CPT::LEGACY_META_MAP; foreach ($manifest['records'] as $cpt => $recs) { if (!is_array($recs)) { continue; diff --git a/includes/class-opentrust-render.php b/includes/class-ettic-otc-render.php similarity index 91% rename from includes/class-opentrust-render.php rename to includes/class-ettic-otc-render.php index 723acd9..3cc529d 100644 --- a/includes/class-opentrust-render.php +++ b/includes/class-ettic-otc-render.php @@ -12,7 +12,7 @@ exit; } -final class OpenTrust_Render { +final class Ettic_OTC_Render { private static ?self $instance = null; @@ -39,7 +39,7 @@ public function dispatch(string $page): void { // ────────────────────────────────────────────── private function render_chat_page(): void { - $ot_settings = OpenTrust::get_settings(); + $ot_settings = Ettic_OTC::get_settings(); $ot_data = $this->gather_data($ot_settings); $ot_data['view'] = 'chat'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only prefill of search box on public chat page. @@ -63,14 +63,14 @@ private function render_chat_page(): void { // Never cache the chat page (fresh nonce required every load). // Set session cookie BEFORE any header() / body output. - if (class_exists('OpenTrust_Chat_Budget')) { - OpenTrust_Chat_Budget::ensure_session_cookie(); + if (class_exists('Ettic_OTC_Chat_Budget')) { + Ettic_OTC_Chat_Budget::ensure_session_cookie(); } header('Content-Type: text/html; charset=utf-8'); header('Cache-Control: no-store, no-cache, must-revalidate, private'); header('Pragma: no-cache'); - include OPENTRUST_PLUGIN_DIR . 'templates/chat.php'; + include ETTIC_OTC_PLUGIN_DIR . 'templates/chat.php'; } /** @@ -84,7 +84,7 @@ private function handle_chat_noscript_post(array $settings): array { } $question = isset($_POST['question']) ? sanitize_textarea_field((string) wp_unslash($_POST['question'])) : ''; - $max_len = (int) ($settings['ai_max_message_length'] ?? OpenTrust_Chat::DEFAULT_MAX_MESSAGE_LENGTH); + $max_len = (int) ($settings['ai_max_message_length'] ?? Ettic_OTC_Chat::DEFAULT_MAX_MESSAGE_LENGTH); if ($question === '') { return ['error' => __('Please enter a question.', 'opentrust')]; } @@ -92,30 +92,30 @@ private function handle_chat_noscript_post(array $settings): array { $question = substr($question, 0, $max_len); } - $adapter = OpenTrust_Chat_Provider::for((string) $settings['ai_provider']); - $api_key = OpenTrust_Chat_Secrets::get((string) $settings['ai_provider']); + $adapter = Ettic_OTC_Chat_Provider::for((string) $settings['ai_provider']); + $api_key = Ettic_OTC_Chat_Secrets::get((string) $settings['ai_provider']); if (!$adapter || $api_key === null) { return ['error' => __('AI chat is not configured.', 'opentrust')]; } $locale = (string) determine_locale(); - $corpus = OpenTrust_Chat_Corpus::get_or_build($locale); + $corpus = Ettic_OTC_Chat_Corpus::get_or_build($locale); // Build a chat request identical to the REST handler's blocking path. // The system prompt + index + tool surface come from the same shared // builder so the noscript path is byte-equivalent to the streaming // one — we just don't get to stream the response. $args = [ - 'system' => OpenTrust_Chat::build_system_prompt($settings, $corpus), + 'system' => Ettic_OTC_Chat::build_system_prompt($settings, $corpus), 'corpus' => $corpus, 'messages' => [['role' => 'user', 'content' => $question]], - 'tools' => OpenTrust_Chat::tool_definitions(), + 'tools' => Ettic_OTC_Chat::tool_definitions(), 'model' => (string) $settings['ai_model'], 'api_key' => $api_key, 'settings' => $settings, ]; - $collector = new OpenTrust_Chat_Stream_Collector($corpus['urls'] ?? []); + $collector = new Ettic_OTC_Chat_Stream_Collector($corpus['urls'] ?? []); $on_chunk = static function (array $event) use ($collector): void { $collector->ingest($event); // noscript path is blocking; never forwards @@ -124,7 +124,7 @@ private function handle_chat_noscript_post(array $settings): array { // Per-request loop detection map — same contract as the REST path. $seen_calls = []; $tool_resolver = static function (string $name, array $args) use ($corpus, &$seen_calls): array { - return OpenTrust_Chat::resolve_tool($name, $args, $corpus, $seen_calls); + return Ettic_OTC_Chat::resolve_tool($name, $args, $corpus, $seen_calls); }; try { @@ -155,7 +155,7 @@ private function compute_chat_state(array $settings): string { if (empty($settings['ai_enabled']) || empty($settings['ai_provider']) || empty($settings['ai_model'])) { return 'unconfigured'; } - if (OpenTrust_Chat_Secrets::get((string) $settings['ai_provider']) === null) { + if (Ettic_OTC_Chat_Secrets::get((string) $settings['ai_provider']) === null) { return 'unconfigured'; } return 'ready'; @@ -166,11 +166,11 @@ private function compute_chat_state(array $settings): string { // ────────────────────────────────────────────── private function render_trust_center(): void { - $ot_settings = OpenTrust::get_settings(); + $ot_settings = Ettic_OTC::get_settings(); $ot_data = $this->gather_data($ot_settings); header('Content-Type: text/html; charset=utf-8'); - include OPENTRUST_PLUGIN_DIR . 'templates/trust-center.php'; + include ETTIC_OTC_PLUGIN_DIR . 'templates/trust-center.php'; } // ────────────────────────────────────────────── @@ -186,7 +186,7 @@ private function render_policy_single(): void { return; } - $ot_settings = OpenTrust::get_settings(); + $ot_settings = Ettic_OTC::get_settings(); $ot_data = $this->gather_data($ot_settings); $ot_data['current_policy'] = $policy; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Core WordPress filter @@ -198,7 +198,7 @@ private function render_policy_single(): void { $ot_data['view'] = 'policy_single'; header('Content-Type: text/html; charset=utf-8'); - include OPENTRUST_PLUGIN_DIR . 'templates/trust-center.php'; + include ETTIC_OTC_PLUGIN_DIR . 'templates/trust-center.php'; } // ────────────────────────────────────────────── @@ -218,7 +218,7 @@ private function render_policy_version(): void { // Current version — redirect to canonical. $current_version = (int) get_post_meta($policy->ID, '_opentrust_version', true) ?: 1; if ($version === $current_version) { - $settings = OpenTrust::get_settings(); + $settings = Ettic_OTC::get_settings(); $base = home_url('/' . $settings['endpoint_slug'] . '/policy/' . $policy->post_name . '/'); wp_safe_redirect($base, 301); exit; @@ -239,7 +239,7 @@ private function render_policy_version(): void { return; } - $ot_settings = OpenTrust::get_settings(); + $ot_settings = Ettic_OTC::get_settings(); $ot_data = $this->gather_data($ot_settings); $ot_data['current_policy'] = $policy; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Core WordPress filter @@ -251,7 +251,7 @@ private function render_policy_version(): void { $ot_data['view'] = 'policy_single'; header('Content-Type: text/html; charset=utf-8'); - include OPENTRUST_PLUGIN_DIR . 'templates/trust-center.php'; + include ETTIC_OTC_PLUGIN_DIR . 'templates/trust-center.php'; } // ────────────────────────────────────────────── @@ -260,15 +260,15 @@ private function render_policy_version(): void { private function render_404(): void { status_header(404); - $settings = OpenTrust::get_settings(); - $hsl = OpenTrust::hex_to_hsl($settings['accent_color'] ?? '#2563EB'); + $settings = Ettic_OTC::get_settings(); + $hsl = Ettic_OTC::hex_to_hsl($settings['accent_color'] ?? '#2563EB'); header('Content-Type: text/html; charset=utf-8'); echo 'Not Found'; echo ''; echo '

'; } @@ -277,15 +277,15 @@ private function render_404(): void { // ────────────────────────────────────────────── public function gather_data(array $settings): array { - $hsl = OpenTrust::hex_to_hsl($settings['accent_color'] ?? '#2563EB'); - $repo = OpenTrust_Repository::instance(); + $hsl = Ettic_OTC::hex_to_hsl($settings['accent_color'] ?? '#2563EB'); + $repo = Ettic_OTC_Repository::instance(); $data = [ 'settings' => $settings, 'hsl' => $hsl, 'logo_url' => '', 'avatar_url' => '', - 'base_url' => home_url('/' . ($settings['endpoint_slug'] ?? OpenTrust::DEFAULT_ENDPOINT_SLUG) . '/'), + 'base_url' => home_url('/' . ($settings['endpoint_slug'] ?? Ettic_OTC::DEFAULT_ENDPOINT_SLUG) . '/'), 'view' => 'main', 'certifications' => [], 'policies' => [], @@ -313,11 +313,11 @@ public function gather_data(array $settings): array { // gate is consumer-layer concern. $visible = $settings['sections_visible'] ?? []; $section_cpt_map = [ - 'certifications' => OpenTrust_CPT::CERTIFICATION, - 'policies' => OpenTrust_CPT::POLICY, - 'subprocessors' => OpenTrust_CPT::SUBPROCESSOR, - 'data_practices' => OpenTrust_CPT::DATA_PRACTICE, - 'faqs' => OpenTrust_CPT::FAQ, + 'certifications' => Ettic_OTC_CPT::CERTIFICATION, + 'policies' => Ettic_OTC_CPT::POLICY, + 'subprocessors' => Ettic_OTC_CPT::SUBPROCESSOR, + 'data_practices' => Ettic_OTC_CPT::DATA_PRACTICE, + 'faqs' => Ettic_OTC_CPT::FAQ, ]; if (!empty($visible['certifications'])) { @@ -370,8 +370,8 @@ private function is_future_dated(\WP_Post $policy): bool { * Returns an array of ['version' => int, 'date' => string, 'url' => string, 'current' => bool]. */ private function get_policy_versions(\WP_Post $policy): array { - $settings = OpenTrust::get_settings(); - $endpoint = $settings['endpoint_slug'] ?? OpenTrust::DEFAULT_ENDPOINT_SLUG; + $settings = Ettic_OTC::get_settings(); + $endpoint = $settings['endpoint_slug'] ?? Ettic_OTC::DEFAULT_ENDPOINT_SLUG; $current_version = (int) get_post_meta($policy->ID, '_opentrust_version', true) ?: 1; $current_url = home_url('/' . $endpoint . '/policy/' . $policy->post_name . '/'); @@ -482,7 +482,7 @@ private function find_policy_by_slug(string $slug): ?\WP_Post { } $posts = get_posts([ - 'post_type' => OpenTrust_CPT::POLICY, + 'post_type' => Ettic_OTC_CPT::POLICY, 'name' => $slug, 'posts_per_page' => 1, 'post_status' => 'publish', @@ -492,7 +492,7 @@ private function find_policy_by_slug(string $slug): ?\WP_Post { } private function get_policy_meta(int $post_id): array { - $repo = OpenTrust_Repository::instance(); + $repo = Ettic_OTC_Repository::instance(); return [ 'ref_id' => (string) (get_post_meta($post_id, '_opentrust_policy_ref_id', true) ?: ''), 'category' => get_post_meta($post_id, '_opentrust_policy_category', true) ?: 'other', diff --git a/includes/class-opentrust-repository.php b/includes/class-ettic-otc-repository.php similarity index 95% rename from includes/class-opentrust-repository.php rename to includes/class-ettic-otc-repository.php index 2c58b23..974d9db 100644 --- a/includes/class-opentrust-repository.php +++ b/includes/class-ettic-otc-repository.php @@ -3,7 +3,7 @@ * Read-side data layer for the trust center. * * Single source of truth for "what published trust-center items exist." Owns - * all DB fetching for the five OpenTrust CPTs and the per-CPT projection + * all DB fetching for the five Ettic_OTC CPTs and the per-CPT projection * shape consumed by Render (templates) and Chat_Corpus (AI corpus index). * * Returns ALL published items unconditionally — no visibility filtering, no @@ -25,7 +25,7 @@ exit; } -final class OpenTrust_Repository { +final class Ettic_OTC_Repository { private static ?self $instance = null; @@ -44,7 +44,7 @@ public function fetch_certifications(): array { return $this->cached_query( 'certifications', [ - 'post_type' => OpenTrust_CPT::CERTIFICATION, + 'post_type' => Ettic_OTC_CPT::CERTIFICATION, 'posts_per_page' => -1, 'post_status' => 'publish', 'orderby' => 'menu_order title', @@ -76,7 +76,7 @@ public function fetch_policies(): array { return $this->cached_query( 'policies', [ - 'post_type' => OpenTrust_CPT::POLICY, + 'post_type' => Ettic_OTC_CPT::POLICY, 'posts_per_page' => -1, 'post_status' => 'publish', 'orderby' => 'meta_value_num title', @@ -112,7 +112,7 @@ public function fetch_subprocessors(): array { return $this->cached_query( 'subprocessors', [ - 'post_type' => OpenTrust_CPT::SUBPROCESSOR, + 'post_type' => Ettic_OTC_CPT::SUBPROCESSOR, 'posts_per_page' => -1, 'post_status' => 'publish', 'orderby' => 'title', @@ -137,7 +137,7 @@ public function fetch_data_practices(): array { return $this->cached_query( 'data_practices', [ - 'post_type' => OpenTrust_CPT::DATA_PRACTICE, + 'post_type' => Ettic_OTC_CPT::DATA_PRACTICE, 'posts_per_page' => -1, 'post_status' => 'publish', 'orderby' => 'meta_value_num title', @@ -169,12 +169,12 @@ static function (WP_Post $post): array { * @return array> */ public function fetch_faqs(): array { - $endpoint = OpenTrust::get_settings()['endpoint_slug'] ?? OpenTrust::DEFAULT_ENDPOINT_SLUG; + $endpoint = Ettic_OTC::get_settings()['endpoint_slug'] ?? Ettic_OTC::DEFAULT_ENDPOINT_SLUG; return $this->cached_query( 'faqs', [ - 'post_type' => OpenTrust_CPT::FAQ, + 'post_type' => Ettic_OTC_CPT::FAQ, 'posts_per_page' => -1, 'post_status' => 'publish', 'orderby' => ['menu_order' => 'ASC', 'title' => 'ASC'], @@ -214,7 +214,7 @@ static function (WP_Post $post) use ($endpoint): array { */ public function fetch_policy_posts(): array { return get_posts([ - 'post_type' => OpenTrust_CPT::POLICY, + 'post_type' => Ettic_OTC_CPT::POLICY, 'posts_per_page' => -1, 'post_status' => 'publish', 'orderby' => 'title', @@ -252,7 +252,7 @@ public function section_last_updated(string $post_type): string { /** * Build a locale-and-version-scoped transient key. The locale suffix keeps * WPML/Polylang variants in separate buckets; the version counter - * (opentrust_cache_version, bumped by OpenTrust::invalidate_cache) lets a + * (opentrust_cache_version, bumped by Ettic_OTC::invalidate_cache) lets a * single option flip bust every cached locale at once. */ private function cache_key(string $bucket): string { diff --git a/includes/class-opentrust-version.php b/includes/class-ettic-otc-version.php similarity index 97% rename from includes/class-opentrust-version.php rename to includes/class-ettic-otc-version.php index 4261057..f5380c7 100644 --- a/includes/class-opentrust-version.php +++ b/includes/class-ettic-otc-version.php @@ -16,7 +16,7 @@ exit; } -final class OpenTrust_Version { +final class Ettic_OTC_Version { private static ?self $instance = null; @@ -126,7 +126,7 @@ public function add_version_history_meta_box(): void { 'opentrust_version_history', __('Version History', 'opentrust'), [$this, 'render_version_history'], - OpenTrust_CPT::POLICY, + Ettic_OTC_CPT::POLICY, 'side', 'default' ); @@ -139,8 +139,8 @@ public function render_version_history(\WP_Post $post): void { 'order' => 'DESC', ]); - $settings = OpenTrust::get_settings(); - $slug = $settings['endpoint_slug'] ?? OpenTrust::DEFAULT_ENDPOINT_SLUG; + $settings = Ettic_OTC::get_settings(); + $slug = $settings['endpoint_slug'] ?? Ettic_OTC::DEFAULT_ENDPOINT_SLUG; $post_slug = $post->post_name ?: sanitize_title($post->post_title); if (empty($revisions)) { diff --git a/includes/class-opentrust.php b/includes/class-ettic-otc.php similarity index 93% rename from includes/class-opentrust.php rename to includes/class-ettic-otc.php index 9a804c5..43960dd 100644 --- a/includes/class-opentrust.php +++ b/includes/class-ettic-otc.php @@ -9,7 +9,7 @@ exit; } -final class OpenTrust { +final class Ettic_OTC { /** * Default URL path the trust center mounts at when the operator hasn't @@ -33,17 +33,17 @@ private function __construct() { // Flush rewrite rules when settings change (transient flag). add_action('init', [$this, 'maybe_flush_rewrites'], 99); - // Bump the render-cache version on any OpenTrust CPT change. Catches + // Bump the render-cache version on any Ettic_OTC CPT change. Catches // saves, deletes, trash/untrash, and publish transitions in one wire-up. - OpenTrust_CPT::register_invalidator(OpenTrust_CPT::ALL, [$this, 'invalidate_cache']); + Ettic_OTC_CPT::register_invalidator(Ettic_OTC_CPT::ALL, [$this, 'invalidate_cache']); // Boot sub-systems. - OpenTrust_CPT::instance(); - OpenTrust_Version::instance(); - OpenTrust_Chat::instance(); + Ettic_OTC_CPT::instance(); + Ettic_OTC_Version::instance(); + Ettic_OTC_Chat::instance(); if (is_admin()) { - OpenTrust_Admin::instance(); + Ettic_OTC_Admin::instance(); } } @@ -86,7 +86,7 @@ public static function defaults(): array { 'company_registration' => '', 'vat_number' => '', - // Per-site salt — written out-of-band by OpenTrust_Chat_Budget::site_salt() + // Per-site salt — written out-of-band by Ettic_OTC_Chat_Budget::site_salt() // on first access. Empty here so a fresh install starts in the // "needs lazy generation" state; once written, sanitize_settings // carries it forward byte-for-byte. @@ -102,11 +102,11 @@ public static function defaults(): array { // expired or the provider has deprecated the model id. 'ai_model_display_name' => '', 'ai_model_recommended' => false, - 'ai_daily_token_budget' => OpenTrust_Chat_Budget::DEFAULT_DAILY_TOKEN_BUDGET, - 'ai_monthly_token_budget' => OpenTrust_Chat_Budget::DEFAULT_MONTHLY_TOKEN_BUDGET, - 'ai_rate_limit_per_ip' => OpenTrust_Chat_Budget::DEFAULT_RATE_LIMIT_PER_IP, - 'ai_rate_limit_per_session' => OpenTrust_Chat_Budget::DEFAULT_RATE_LIMIT_PER_SESSION, - 'ai_max_message_length' => OpenTrust_Chat::DEFAULT_MAX_MESSAGE_LENGTH, + 'ai_daily_token_budget' => Ettic_OTC_Chat_Budget::DEFAULT_DAILY_TOKEN_BUDGET, + 'ai_monthly_token_budget' => Ettic_OTC_Chat_Budget::DEFAULT_MONTHLY_TOKEN_BUDGET, + 'ai_rate_limit_per_ip' => Ettic_OTC_Chat_Budget::DEFAULT_RATE_LIMIT_PER_IP, + 'ai_rate_limit_per_session' => Ettic_OTC_Chat_Budget::DEFAULT_RATE_LIMIT_PER_SESSION, + 'ai_max_message_length' => Ettic_OTC_Chat::DEFAULT_MAX_MESSAGE_LENGTH, 'ai_contact_url' => '', 'ai_show_model_attribution' => true, 'ai_logging_enabled' => true, @@ -184,7 +184,7 @@ public function maybe_render_trust_center(): void { return; } - OpenTrust_Render::instance()->dispatch($page); + Ettic_OTC_Render::instance()->dispatch($page); exit; } @@ -194,7 +194,7 @@ public function maybe_render_trust_center(): void { public function invalidate_cache(): void { // Bump a single version counter instead of deleting locale-specific - // transient keys one by one. OpenTrust_Render::cache_key() includes + // transient keys one by one. Ettic_OTC_Render::cache_key() includes // this version in every key, so every cached locale variant is // instantly stale after the bump. Stale transients expire naturally // on their existing TTL and are garbage-collected by WordPress. @@ -216,7 +216,7 @@ public function invalidate_cache(): void { public static function debug_log(string $message): void { if (defined('WP_DEBUG') && WP_DEBUG) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- debug-gated diagnostic, only fires under WP_DEBUG - error_log('[OpenTrust] ' . $message); + error_log('[Ettic_OTC] ' . $message); } } diff --git a/includes/data/data-practice-catalog.php b/includes/data/data-practice-catalog.php index 18108b0..01b2d7d 100644 --- a/includes/data/data-practice-catalog.php +++ b/includes/data/data-practice-catalog.php @@ -10,7 +10,7 @@ * * Extend without forking via the `opentrust_data_practice_catalog` filter. * - * Legal basis values must match keys in OpenTrust_Render::legal_basis_labels(). + * Legal basis values must match keys in Ettic_OTC_Render::legal_basis_labels(). */ declare(strict_types=1); diff --git a/includes/providers/class-opentrust-chat-provider-anthropic.php b/includes/providers/class-ettic-otc-chat-provider-anthropic.php similarity index 99% rename from includes/providers/class-opentrust-chat-provider-anthropic.php rename to includes/providers/class-ettic-otc-chat-provider-anthropic.php index 322da1d..8f2de9e 100644 --- a/includes/providers/class-opentrust-chat-provider-anthropic.php +++ b/includes/providers/class-ettic-otc-chat-provider-anthropic.php @@ -13,7 +13,7 @@ exit; } -final class OpenTrust_Chat_Provider_Anthropic extends OpenTrust_Chat_Provider { +final class Ettic_OTC_Chat_Provider_Anthropic extends Ettic_OTC_Chat_Provider { private const MODELS_ENDPOINT = 'https://api.anthropic.com/v1/models'; private const MESSAGES_ENDPOINT = 'https://api.anthropic.com/v1/messages'; @@ -482,7 +482,7 @@ private function handle_anthropic_sse_line(string $line, array &$state): void { } /** - * Transform a citation delta into a normalized OpenTrust citation event. + * Transform a citation delta into a normalized Ettic_OTC citation event. * * Anthropic emits `search_result_location` citations for content returned * by tools that produced search_result blocks. The canonical URL lives on diff --git a/includes/providers/class-opentrust-chat-provider-openai.php b/includes/providers/class-ettic-otc-chat-provider-openai.php similarity index 98% rename from includes/providers/class-opentrust-chat-provider-openai.php rename to includes/providers/class-ettic-otc-chat-provider-openai.php index d8dcf57..c009d5a 100644 --- a/includes/providers/class-opentrust-chat-provider-openai.php +++ b/includes/providers/class-ettic-otc-chat-provider-openai.php @@ -13,7 +13,7 @@ exit; } -class OpenTrust_Chat_Provider_OpenAI extends OpenTrust_Chat_Provider { +class Ettic_OTC_Chat_Provider_OpenAI extends Ettic_OTC_Chat_Provider { protected const API_BASE = 'https://api.openai.com'; protected const MODELS_ENDPOINT = 'https://api.openai.com/v1/models'; @@ -168,7 +168,7 @@ protected function initialize_turn_loop(array $args, callable $on_chunk): ?array } // The system prompt arrives pre-built with the corpus index already - // appended (see OpenTrust_Chat::build_system_prompt). Tack on a tail + // appended (see Ettic_OTC_Chat::build_system_prompt). Tack on a tail // that sets up the inline-citation contract — Anthropic uses native // search_result_location citations and doesn't need this block. $system_full = $this->append_citation_instructions($system); @@ -358,7 +358,7 @@ protected function extra_stream_headers(): array { /** * Append the OpenAI/OpenRouter-specific citation contract to the base * system prompt. The base prompt already contains the corpus index and - * the role rules — see OpenTrust_Chat::build_system_prompt(). All we + * the role rules — see Ettic_OTC_Chat::build_system_prompt(). All we * add is how this provider should mark citations inline so the server * can convert them into structured citation events. * @@ -508,7 +508,7 @@ private function handle_openai_sse_line(string $line, array &$state): void { /** * Scan the full answer for [[cite:doc-id]] tags and emit citation events * with URLs resolved from the corpus. Unknown IDs are ignored here; - * URL whitelist enforcement happens upstream in OpenTrust_Chat. + * URL whitelist enforcement happens upstream in Ettic_OTC_Chat. */ private function extract_and_emit_citations(string $answer, array $documents, callable $on_chunk): void { if ($answer === '' || empty($documents)) { diff --git a/includes/providers/class-opentrust-chat-provider-openrouter.php b/includes/providers/class-ettic-otc-chat-provider-openrouter.php similarity index 93% rename from includes/providers/class-opentrust-chat-provider-openrouter.php rename to includes/providers/class-ettic-otc-chat-provider-openrouter.php index 472afdd..ea8caf2 100644 --- a/includes/providers/class-opentrust-chat-provider-openrouter.php +++ b/includes/providers/class-ettic-otc-chat-provider-openrouter.php @@ -16,7 +16,7 @@ exit; } -final class OpenTrust_Chat_Provider_OpenRouter extends OpenTrust_Chat_Provider_OpenAI { +final class Ettic_OTC_Chat_Provider_OpenRouter extends Ettic_OTC_Chat_Provider_OpenAI { protected const API_BASE = 'https://openrouter.ai'; protected const MODELS_ENDPOINT = 'https://openrouter.ai/api/v1/models'; @@ -106,9 +106,9 @@ protected function is_recommended(string $id): bool { protected function extra_stream_headers(): array { return [ 'HTTP-Referer' => home_url('/'), - 'X-Title' => (string) (OpenTrust::get_settings()['company_name'] ?? 'OpenTrust'), + 'X-Title' => (string) (Ettic_OTC::get_settings()['company_name'] ?? 'Open Trust Center by Ettic'), ]; } - // stream_chat() is inherited from OpenTrust_Chat_Provider_OpenAI. + // stream_chat() is inherited from Ettic_OTC_Chat_Provider_OpenAI. } diff --git a/includes/providers/class-opentrust-chat-provider.php b/includes/providers/class-ettic-otc-chat-provider.php similarity index 98% rename from includes/providers/class-opentrust-chat-provider.php rename to includes/providers/class-ettic-otc-chat-provider.php index 4d4b036..7083cb2 100644 --- a/includes/providers/class-opentrust-chat-provider.php +++ b/includes/providers/class-ettic-otc-chat-provider.php @@ -3,9 +3,9 @@ * Abstract base class for chat providers. * * Concrete implementations: - * - OpenTrust_Chat_Provider_Anthropic - * - OpenTrust_Chat_Provider_OpenAI - * - OpenTrust_Chat_Provider_OpenRouter + * - Ettic_OTC_Chat_Provider_Anthropic + * - Ettic_OTC_Chat_Provider_OpenAI + * - Ettic_OTC_Chat_Provider_OpenRouter * * The base class provides the factory, shared HTTP helpers, and a * host allowlist for SSRF prevention. Subclasses implement the @@ -20,16 +20,16 @@ exit; } -abstract class OpenTrust_Chat_Provider { +abstract class Ettic_OTC_Chat_Provider { /** * Factory: return a provider instance for a settings slug. */ public static function for(string $provider_slug): ?self { return match ($provider_slug) { - 'anthropic' => new OpenTrust_Chat_Provider_Anthropic(), - 'openai' => new OpenTrust_Chat_Provider_OpenAI(), - 'openrouter' => new OpenTrust_Chat_Provider_OpenRouter(), + 'anthropic' => new Ettic_OTC_Chat_Provider_Anthropic(), + 'openai' => new Ettic_OTC_Chat_Provider_OpenAI(), + 'openrouter' => new Ettic_OTC_Chat_Provider_OpenRouter(), default => null, }; } @@ -160,7 +160,7 @@ final public function stream_chat(array $args, callable $on_chunk, callable $too // and answer from training data. After any tool call we relax to auto. $has_called_tool = false; - for ($turn = 1; $turn <= OpenTrust_Chat::MAX_TOOL_TURNS; $turn++) { + for ($turn = 1; $turn <= Ettic_OTC_Chat::MAX_TOOL_TURNS; $turn++) { $stream_state = $this->stream_one_turn($turn_loop_state, $has_called_tool, $on_chunk); if ($stream_state === null) { return; // stream_one_turn already emitted an error event @@ -654,7 +654,7 @@ final protected function stream_post(string $url, array $payload, array $headers $state->error_body = $state->buffer; } $detail = $this->describe_streaming_error($state->error_body, $state->response_headers, $http_code); - OpenTrust::debug_log($detail); + Ettic_OTC::debug_log($detail); return ['ok' => false, 'code' => $http_code, 'error' => $detail]; } diff --git a/open-trust-center-by-ettic.php b/open-trust-center-by-ettic.php index 6500d5c..790b733 100644 --- a/open-trust-center-by-ettic.php +++ b/open-trust-center-by-ettic.php @@ -18,79 +18,79 @@ defined('ABSPATH') || exit; -define('OPENTRUST_VERSION', '1.2.0'); -define('OPENTRUST_PLUGIN_DIR', plugin_dir_path(__FILE__)); -define('OPENTRUST_PLUGIN_URL', plugin_dir_url(__FILE__)); -define('OPENTRUST_PLUGIN_FILE', __FILE__); -define('OPENTRUST_DB_VERSION', 1); +define('ETTIC_OTC_VERSION', '1.2.0'); +define('ETTIC_OTC_PLUGIN_DIR', plugin_dir_path(__FILE__)); +define('ETTIC_OTC_PLUGIN_URL', plugin_dir_url(__FILE__)); +define('ETTIC_OTC_PLUGIN_FILE', __FILE__); +define('ETTIC_OTC_DB_VERSION', 1); -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-admin.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-admin-settings.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-admin-questions.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-admin-ai.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-admin-review.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-cpt.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-catalog.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-repository.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-render.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-version.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-io.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-admin-tools.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-admin.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-admin-settings.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-admin-questions.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-admin-ai.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-admin-review.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-cpt.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-catalog.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-repository.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-render.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-version.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-io.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-admin-tools.php'; // Chat (OTC) — policy chat feature. -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-chat-secrets.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/providers/class-opentrust-chat-provider.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/providers/class-opentrust-chat-provider-anthropic.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/providers/class-opentrust-chat-provider-openai.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/providers/class-opentrust-chat-provider-openrouter.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-chat-search.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-chat-corpus.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-chat-budget.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-chat-log.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-chat-summarizer.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-chat-stream-collector.php'; -require_once OPENTRUST_PLUGIN_DIR . 'includes/class-opentrust-chat.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-chat-secrets.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/providers/class-ettic-otc-chat-provider.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/providers/class-ettic-otc-chat-provider-anthropic.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/providers/class-ettic-otc-chat-provider-openai.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/providers/class-ettic-otc-chat-provider-openrouter.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-chat-search.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-chat-corpus.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-chat-budget.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-chat-log.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-chat-summarizer.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-chat-stream-collector.php'; +require_once ETTIC_OTC_PLUGIN_DIR . 'includes/class-ettic-otc-chat.php'; add_action('plugins_loaded', static function (): void { - OpenTrust::instance(); + Ettic_OTC::instance(); }); register_activation_hook(__FILE__, static function (): void { // Register CPTs before flushing so rewrite rules include them. - OpenTrust_CPT::register_post_types(); + Ettic_OTC_CPT::register_post_types(); // First-install defaults. Autoload=no — the option is a sizeable array // carrying encrypted Turnstile secret + per-site salt, and we'd rather - // not load it on every front-end request that never touches OpenTrust. + // not load it on every front-end request that never touches Ettic_OTC. if (false === get_option('opentrust_settings')) { - add_option('opentrust_settings', OpenTrust::defaults(), '', false); + add_option('opentrust_settings', Ettic_OTC::defaults(), '', false); } // Custom tables. - OpenTrust_Chat_Log::create_table(); + Ettic_OTC_Chat_Log::create_table(); // Stamp the schema version on a true first install only. Future schema // changes (none today) would bump this constant and re-check here. if (false === get_option('opentrust_db_version', false)) { - update_option('opentrust_db_version', OPENTRUST_DB_VERSION, false); + update_option('opentrust_db_version', ETTIC_OTC_DB_VERSION, false); } // Seed default FAQs on first activation. Gated internally so deletions // stick and re-activation will not recreate them. - OpenTrust_Catalog::seed_default_faqs(); + Ettic_OTC_Catalog::seed_default_faqs(); // Schedule crons. - OpenTrust_Chat_Log::schedule_cron(); - OpenTrust_Admin_AI::schedule_cron(); + Ettic_OTC_Chat_Log::schedule_cron(); + Ettic_OTC_Admin_AI::schedule_cron(); // Add rewrite rules and flush. - OpenTrust::add_rewrite_rules(); + Ettic_OTC::add_rewrite_rules(); flush_rewrite_rules(); }); register_deactivation_hook(__FILE__, static function (): void { - OpenTrust_Chat_Log::unschedule_cron(); - OpenTrust_Admin_AI::unschedule_cron(); + Ettic_OTC_Chat_Log::unschedule_cron(); + Ettic_OTC_Admin_AI::unschedule_cron(); flush_rewrite_rules(); }); diff --git a/templates/chat.php b/templates/chat.php index bc260e6..df351a7 100644 --- a/templates/chat.php +++ b/templates/chat.php @@ -81,8 +81,8 @@ (int) $ot_hsl['l'], $ot_accent_contrast === '#ffffff' ? '#ffffff' : '#111827' ); - wp_register_style('opentrust-frontend', plugins_url('assets/css/frontend.css', OPENTRUST_PLUGIN_FILE), [], OPENTRUST_VERSION); - wp_register_style('opentrust-chat', plugins_url('assets/css/chat.css', OPENTRUST_PLUGIN_FILE), ['opentrust-frontend'], OPENTRUST_VERSION); + wp_register_style('opentrust-frontend', plugins_url('assets/css/frontend.css', ETTIC_OTC_PLUGIN_FILE), [], ETTIC_OTC_VERSION); + wp_register_style('opentrust-chat', plugins_url('assets/css/chat.css', ETTIC_OTC_PLUGIN_FILE), ['opentrust-frontend'], ETTIC_OTC_VERSION); wp_enqueue_style('opentrust-chat'); wp_add_inline_style('opentrust-chat', $ot_root_vars); wp_print_styles(['opentrust-frontend', 'opentrust-chat']); @@ -150,10 +150,10 @@ - + - + true, 'strategy' => 'defer'] ); wp_enqueue_script('opentrust-chat'); diff --git a/templates/partials/certifications.php b/templates/partials/certifications.php index 9e7772e..bf937b5 100644 --- a/templates/partials/certifications.php +++ b/templates/partials/certifications.php @@ -12,13 +12,13 @@ // phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Template variables are local scope via include() $ot_certifications = $ot_data['certifications'] ?? []; -$ot_audited_labels = OpenTrust_Render::cert_status_labels(); -$ot_aligned_labels = OpenTrust_Render::cert_aligned_status_labels(); +$ot_audited_labels = Ettic_OTC_Render::cert_status_labels(); +$ot_aligned_labels = Ettic_OTC_Render::cert_aligned_status_labels(); ?>
- +

diff --git a/templates/partials/data-practices.php b/templates/partials/data-practices.php index 1221b26..744f415 100644 --- a/templates/partials/data-practices.php +++ b/templates/partials/data-practices.php @@ -16,7 +16,7 @@ // phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Template variables are local scope via include() $ot_practices = $ot_data['data_practices'] ?? []; -$ot_basis_labels = OpenTrust_Render::legal_basis_labels(); +$ot_basis_labels = Ettic_OTC_Render::legal_basis_labels(); if (empty($ot_practices)) { return; @@ -30,7 +30,7 @@
- +

diff --git a/templates/partials/policies.php b/templates/partials/policies.php index 39ad934..a3e0c40 100644 --- a/templates/partials/policies.php +++ b/templates/partials/policies.php @@ -12,7 +12,7 @@ // phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Template variables are local scope via include() $ot_policies = $ot_data['policies'] ?? []; -$ot_category_labels = OpenTrust_Render::policy_category_labels(); +$ot_category_labels = Ettic_OTC_Render::policy_category_labels(); // Show the ID column only when at least one policy has a Policy ID set. $ot_has_ref_col = false; @@ -23,7 +23,7 @@
- +

diff --git a/templates/partials/policy-single.php b/templates/partials/policy-single.php index 8ac9f5e..61f1a64 100644 --- a/templates/partials/policy-single.php +++ b/templates/partials/policy-single.php @@ -19,7 +19,7 @@ $ot_is_pending = $ot_data['is_pending'] ?? false; $ot_versions = $ot_data['policy_versions'] ?? []; -$ot_category_labels = OpenTrust_Render::policy_category_labels(); +$ot_category_labels = Ettic_OTC_Render::policy_category_labels(); $ot_category_label = $ot_category_labels[$ot_meta['category']] ?? $ot_meta['category']; $ot_ref_id = (string) ($ot_meta['ref_id'] ?? ''); $ot_citations = $ot_meta['citations'] ?? []; diff --git a/templates/partials/subprocessors.php b/templates/partials/subprocessors.php index 8bf25bb..07be534 100644 --- a/templates/partials/subprocessors.php +++ b/templates/partials/subprocessors.php @@ -16,7 +16,7 @@
- +

diff --git a/templates/trust-center.php b/templates/trust-center.php index e7ed859..1145c2f 100644 --- a/templates/trust-center.php +++ b/templates/trust-center.php @@ -48,8 +48,8 @@ $ot_ai_enabled = !empty($ot_settings['ai_enabled']) && !empty($ot_settings['ai_provider']) && !empty($ot_settings['ai_model']) - && class_exists('OpenTrust_Chat_Secrets') - && OpenTrust_Chat_Secrets::get((string) $ot_settings['ai_provider']) !== null; + && class_exists('Ettic_OTC_Chat_Secrets') + && Ettic_OTC_Chat_Secrets::get((string) $ot_settings['ai_provider']) !== null; $ot_accent_contrast = ((int) $ot_hsl['l'] < 55) ? '#ffffff' : '#111827'; @@ -62,7 +62,7 @@ // WCAG adjustment — keep their exact colour everywhere, contrast be damned. $ot_accent_l_safe = !empty($ot_settings['accent_force_exact']) ? (int) $ot_hsl['l'] - : OpenTrust::accent_safe_lightness((string) ($ot_settings['accent_color'] ?? '#2563EB')); + : Ettic_OTC::accent_safe_lightness((string) ($ot_settings['accent_color'] ?? '#2563EB')); ?> > @@ -90,7 +90,7 @@ (int) $ot_accent_l_safe, $ot_accent_contrast === '#ffffff' ? '#ffffff' : '#111827' ); - wp_register_style('opentrust-frontend', plugins_url('assets/css/frontend.css', OPENTRUST_PLUGIN_FILE), [], OPENTRUST_VERSION); + wp_register_style('opentrust-frontend', plugins_url('assets/css/frontend.css', ETTIC_OTC_PLUGIN_FILE), [], ETTIC_OTC_VERSION); wp_enqueue_style('opentrust-frontend'); wp_add_inline_style('opentrust-frontend', $ot_root_vars); wp_print_styles(['opentrust-frontend']); @@ -149,39 +149,39 @@
@@ -216,8 +216,8 @@ ?>  ·  - - + +

@@ -227,9 +227,9 @@ true, 'strategy' => 'defer'] ); wp_enqueue_script('opentrust-frontend'); diff --git a/uninstall.php b/uninstall.php index c8a1f06..0dfe9b5 100644 --- a/uninstall.php +++ b/uninstall.php @@ -1,6 +1,6 @@ Date: Sun, 17 May 2026 14:27:53 +0200 Subject: [PATCH 04/18] Phase 4: rename storage identifiers to ettic_otc namespace - Options: opentrust_* to ettic_otc_* (settings, provider_keys, db_version, cache_version, faqs_seeded, site_salt) - Postmeta: _opentrust_* to _ettic_otc_* (59 keys) - Transients: opentrust_* to ettic_otc_* - DB table: wp_opentrust_chat_log to wp_ettic_otc_chat_log - CPT slugs: opentr_* to eotc_* (shorter for 20-char post_type cap) - Cron events: opentrust_* to ettic_otc_* - REST namespace: opentrust/v1 to ettic-otc/v1 - Query var: opentrust to ettic_otc - Admin menu slug: opentrust to ettic-otc - Admin page URLs and screen IDs updated to match - WPML config aligned OpenTrust_CPT::LEGACY_MAP values now point to eotc_* (Phase 8 adds opentr_* entries for full back-compat). Text-domain and JS globals stay for Phases 6 and 9. --- includes/class-ettic-otc-admin-ai.php | 100 +- includes/class-ettic-otc-admin-questions.php | 44 +- includes/class-ettic-otc-admin-review.php | 22 +- includes/class-ettic-otc-admin-settings.php | 104 +- includes/class-ettic-otc-admin-tools.php | 102 +- includes/class-ettic-otc-admin.php | 42 +- includes/class-ettic-otc-catalog.php | 28 +- includes/class-ettic-otc-chat-budget.php | 28 +- includes/class-ettic-otc-chat-corpus.php | 14 +- includes/class-ettic-otc-chat-log.php | 6 +- includes/class-ettic-otc-chat-secrets.php | 14 +- includes/class-ettic-otc-chat-summarizer.php | 12 +- includes/class-ettic-otc-chat.php | 10 +- includes/class-ettic-otc-cpt.php | 496 +++--- includes/class-ettic-otc-io.php | 143 +- includes/class-ettic-otc-render.php | 38 +- includes/class-ettic-otc-repository.php | 76 +- includes/class-ettic-otc-version.php | 26 +- includes/class-ettic-otc.php | 28 +- includes/data/certification-catalog.php | 142 +- includes/data/data-practice-catalog.php | 124 +- includes/data/faq-catalog.php | 6 +- includes/data/subprocessor-catalog.php | 1644 +++++++++--------- open-trust-center-by-ettic.php | 8 +- templates/chat.php | 24 +- templates/trust-center.php | 14 +- uninstall.php | 44 +- wpml-config.xml | 72 +- 28 files changed, 1703 insertions(+), 1708 deletions(-) diff --git a/includes/class-ettic-otc-admin-ai.php b/includes/class-ettic-otc-admin-ai.php index b33c718..41a4c06 100644 --- a/includes/class-ettic-otc-admin-ai.php +++ b/includes/class-ettic-otc-admin-ai.php @@ -27,7 +27,7 @@ final class Ettic_OTC_Admin_AI { - public const CRON_HOOK = 'opentrust_ai_models_refresh'; + public const CRON_HOOK = 'ettic_otc_ai_models_refresh'; public const CACHE_TTL = 25 * HOUR_IN_SECONDS; // Slightly > daily cron cadence so the cache never expires between ticks. private static ?self $instance = null; @@ -37,10 +37,10 @@ public static function instance(): self { } private function __construct() { - add_action('admin_post_opentrust_ai_save_key', [$this, 'handle_ai_save_key']); - add_action('admin_post_opentrust_ai_forget_key', [$this, 'handle_ai_forget_key']); - add_action('admin_post_opentrust_ai_refresh_models', [$this, 'handle_ai_refresh_models']); - add_action('admin_post_opentrust_ai_summarize_sweep', [$this, 'handle_ai_summarize_sweep']); + add_action('admin_post_ettic_otc_ai_save_key', [$this, 'handle_ai_save_key']); + add_action('admin_post_ettic_otc_ai_forget_key', [$this, 'handle_ai_forget_key']); + add_action('admin_post_ettic_otc_ai_refresh_models', [$this, 'handle_ai_refresh_models']); + add_action('admin_post_ettic_otc_ai_summarize_sweep', [$this, 'handle_ai_summarize_sweep']); // Idempotent re-schedule on admin page loads — defends against the // daily cron getting cleared externally without forcing a deactivate/ @@ -59,9 +59,9 @@ public function render_ai_tab(array $settings): void { $is_non_anthropic_active = $has_active_key && $active_provider !== 'anthropic'; // Surface any transient notice from the admin-post handlers. - $notice = get_transient('opentrust_ai_notice_' . get_current_user_id()); + $notice = get_transient('ettic_otc_ai_notice_' . get_current_user_id()); if (is_array($notice)) { - delete_transient('opentrust_ai_notice_' . get_current_user_id()); + delete_transient('ettic_otc_ai_notice_' . get_current_user_id()); $class = $notice['type'] === 'error' ? 'notice-error' : 'notice-success'; printf( '

%s

', @@ -170,8 +170,8 @@ private function render_summary_backfill_banner(array $settings, bool $has_activ

- - + +
@@ -286,8 +286,8 @@ private function render_provider_card(array $provider, array $stored_keys, strin ✓
- - + +
@@ -630,15 +630,15 @@ public function render_policy_meta_box(\WP_Post $post): void {
- +

- - + +

ID, '_opentrust_sub_purpose', true) ?: ''; - $data_processed = get_post_meta($post->ID, '_opentrust_sub_data_processed', true) ?: ''; - $country = get_post_meta($post->ID, '_opentrust_sub_country', true) ?: ''; - $website = get_post_meta($post->ID, '_opentrust_sub_website', true) ?: ''; - $dpa_signed = (bool) get_post_meta($post->ID, '_opentrust_sub_dpa_signed', true); + $purpose = get_post_meta($post->ID, '_ettic_otc_sub_purpose', true) ?: ''; + $data_processed = get_post_meta($post->ID, '_ettic_otc_sub_data_processed', true) ?: ''; + $country = get_post_meta($post->ID, '_ettic_otc_sub_country', true) ?: ''; + $website = get_post_meta($post->ID, '_ettic_otc_sub_website', true) ?: ''; + $dpa_signed = (bool) get_post_meta($post->ID, '_ettic_otc_sub_dpa_signed', true); ?>
- - + +

- - + +

- - + +
- - + +

@@ -690,22 +690,22 @@ public function render_sub_meta_box(\WP_Post $post): void { // ── Data Practice meta box ── public function render_dp_meta_box(\WP_Post $post): void { - wp_nonce_field('opentrust_save_dp', 'opentrust_dp_nonce'); + wp_nonce_field('ettic_otc_save_dp', 'ettic_otc_dp_nonce'); - $data_items = get_post_meta($post->ID, '_opentrust_dp_data_items', true); + $data_items = get_post_meta($post->ID, '_ettic_otc_dp_data_items', true); $data_items = is_array($data_items) ? $data_items : []; - $purpose = get_post_meta($post->ID, '_opentrust_dp_purpose', true) ?: ''; - $legal_basis = get_post_meta($post->ID, '_opentrust_dp_legal_basis', true) ?: ''; - $retention_period = get_post_meta($post->ID, '_opentrust_dp_retention_period', true) ?: ''; - $shared_with = get_post_meta($post->ID, '_opentrust_dp_shared_with', true); + $purpose = get_post_meta($post->ID, '_ettic_otc_dp_purpose', true) ?: ''; + $legal_basis = get_post_meta($post->ID, '_ettic_otc_dp_legal_basis', true) ?: ''; + $retention_period = get_post_meta($post->ID, '_ettic_otc_dp_retention_period', true) ?: ''; + $shared_with = get_post_meta($post->ID, '_ettic_otc_dp_shared_with', true); $shared_with = is_array($shared_with) ? $shared_with : []; - $sort_order = (int) get_post_meta($post->ID, '_opentrust_dp_sort_order', true); + $sort_order = (int) get_post_meta($post->ID, '_ettic_otc_dp_sort_order', true); - $prop_collected = (bool) get_post_meta($post->ID, '_opentrust_dp_collected', true); - $prop_stored = (bool) get_post_meta($post->ID, '_opentrust_dp_stored', true); - $prop_shared = (bool) get_post_meta($post->ID, '_opentrust_dp_shared', true); - $prop_sold = (bool) get_post_meta($post->ID, '_opentrust_dp_sold', true); - $prop_encrypted = (bool) get_post_meta($post->ID, '_opentrust_dp_encrypted', true); + $prop_collected = (bool) get_post_meta($post->ID, '_ettic_otc_dp_collected', true); + $prop_stored = (bool) get_post_meta($post->ID, '_ettic_otc_dp_stored', true); + $prop_shared = (bool) get_post_meta($post->ID, '_ettic_otc_dp_shared', true); + $prop_sold = (bool) get_post_meta($post->ID, '_ettic_otc_dp_sold', true); + $prop_encrypted = (bool) get_post_meta($post->ID, '_ettic_otc_dp_encrypted', true); $basis_options = Ettic_OTC_Render::legal_basis_labels(); ?> @@ -713,11 +713,11 @@ public function render_dp_meta_box(\WP_Post $post): void {
-
+
$item): ?> - + @@ -727,15 +727,15 @@ public function render_dp_meta_box(\WP_Post $post): void {
- - + +
- - $label): ?> @@ -743,19 +743,19 @@ public function render_dp_meta_box(\WP_Post $post): void {
- - + +
-
+
$entry): ?> - + @@ -768,23 +768,23 @@ public function render_dp_meta_box(\WP_Post $post): void {
@@ -793,8 +793,8 @@ public function render_dp_meta_box(\WP_Post $post): void {
- - + +

post_type, self::ALL, true)) { return; } - if (get_post_meta($post_id, '_opentrust_uuid', true)) { + if (get_post_meta($post_id, '_ettic_otc_uuid', true)) { return; } - update_post_meta($post_id, '_opentrust_uuid', wp_generate_uuid4()); + update_post_meta($post_id, '_ettic_otc_uuid', wp_generate_uuid4()); } // ────────────────────────────────────────────── @@ -841,7 +841,7 @@ public function save_meta(int $post_id, \WP_Post $post): void { } private function save_cert_meta(int $post_id): void { - if (!isset($_POST['opentrust_cert_nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['opentrust_cert_nonce'] ) ), 'opentrust_save_cert')) { + if (!isset($_POST['ettic_otc_cert_nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['ettic_otc_cert_nonce'] ) ), 'ettic_otc_save_cert')) { return; } if (!current_user_can('edit_post', $post_id)) { @@ -849,24 +849,24 @@ private function save_cert_meta(int $post_id): void { } $valid_types = ['certified', 'compliant']; - $type = sanitize_text_field( wp_unslash( $_POST['opentrust_cert_type'] ?? 'compliant' ) ); - update_post_meta($post_id, '_opentrust_cert_type', in_array($type, $valid_types, true) ? $type : 'compliant'); + $type = sanitize_text_field( wp_unslash( $_POST['ettic_otc_cert_type'] ?? 'compliant' ) ); + update_post_meta($post_id, '_ettic_otc_cert_type', in_array($type, $valid_types, true) ? $type : 'compliant'); - update_post_meta($post_id, '_opentrust_cert_issuing_body', sanitize_text_field( wp_unslash( $_POST['opentrust_cert_issuing_body'] ?? '' ) )); + update_post_meta($post_id, '_ettic_otc_cert_issuing_body', sanitize_text_field( wp_unslash( $_POST['ettic_otc_cert_issuing_body'] ?? '' ) )); $valid_statuses = ['active', 'in_progress', 'expired']; - $status = sanitize_text_field( wp_unslash( $_POST['opentrust_cert_status'] ?? 'active' ) ); - update_post_meta($post_id, '_opentrust_cert_status', in_array($status, $valid_statuses, true) ? $status : 'active'); - - update_post_meta($post_id, '_opentrust_cert_issue_date', sanitize_text_field( wp_unslash( $_POST['opentrust_cert_issue_date'] ?? '' ) )); - update_post_meta($post_id, '_opentrust_cert_expiry_date', sanitize_text_field( wp_unslash( $_POST['opentrust_cert_expiry_date'] ?? '' ) )); - update_post_meta($post_id, '_opentrust_cert_badge_id', absint( wp_unslash( $_POST['opentrust_cert_badge_id'] ?? 0 ) )); - update_post_meta($post_id, '_opentrust_cert_artifact_id', absint( wp_unslash( $_POST['opentrust_cert_artifact_id'] ?? 0 ) )); - update_post_meta($post_id, '_opentrust_cert_description', sanitize_textarea_field( wp_unslash( $_POST['opentrust_cert_description'] ?? '' ) )); + $status = sanitize_text_field( wp_unslash( $_POST['ettic_otc_cert_status'] ?? 'active' ) ); + update_post_meta($post_id, '_ettic_otc_cert_status', in_array($status, $valid_statuses, true) ? $status : 'active'); + + update_post_meta($post_id, '_ettic_otc_cert_issue_date', sanitize_text_field( wp_unslash( $_POST['ettic_otc_cert_issue_date'] ?? '' ) )); + update_post_meta($post_id, '_ettic_otc_cert_expiry_date', sanitize_text_field( wp_unslash( $_POST['ettic_otc_cert_expiry_date'] ?? '' ) )); + update_post_meta($post_id, '_ettic_otc_cert_badge_id', absint( wp_unslash( $_POST['ettic_otc_cert_badge_id'] ?? 0 ) )); + update_post_meta($post_id, '_ettic_otc_cert_artifact_id', absint( wp_unslash( $_POST['ettic_otc_cert_artifact_id'] ?? 0 ) )); + update_post_meta($post_id, '_ettic_otc_cert_description', sanitize_textarea_field( wp_unslash( $_POST['ettic_otc_cert_description'] ?? '' ) )); } private function save_policy_meta(int $post_id): void { - if (!isset($_POST['opentrust_policy_nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['opentrust_policy_nonce'] ) ), 'opentrust_save_policy')) { + if (!isset($_POST['ettic_otc_policy_nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['ettic_otc_policy_nonce'] ) ), 'ettic_otc_save_policy')) { return; } if (!current_user_can('edit_post', $post_id)) { @@ -874,10 +874,10 @@ private function save_policy_meta(int $post_id): void { } // Version bump — only when explicitly requested by the user. - if (!empty($_POST['opentrust_publish_new_version'])) { + if (!empty($_POST['ettic_otc_publish_new_version'])) { $post = get_post($post_id); if ($post && 'publish' === $post->post_status) { - $summary = sanitize_text_field( wp_unslash( $_POST['opentrust_version_summary'] ?? '' ) ); + $summary = sanitize_text_field( wp_unslash( $_POST['ettic_otc_version_summary'] ?? '' ) ); Ettic_OTC_Version::bump_version($post_id, $summary); } } @@ -885,26 +885,26 @@ private function save_policy_meta(int $post_id): void { // Ensure first-publish posts get v1. Ettic_OTC_Version::ensure_initial_version($post_id); - $ref_id = sanitize_text_field( wp_unslash( $_POST['opentrust_policy_ref_id'] ?? '' ) ); + $ref_id = sanitize_text_field( wp_unslash( $_POST['ettic_otc_policy_ref_id'] ?? '' ) ); // Collapse internal whitespace runs so "POL 012" becomes "POL 012" on save. $ref_id = trim((string) preg_replace('/\s+/u', ' ', $ref_id)); if ($ref_id !== '') { - update_post_meta($post_id, '_opentrust_policy_ref_id', $ref_id); + update_post_meta($post_id, '_ettic_otc_policy_ref_id', $ref_id); } else { - delete_post_meta($post_id, '_opentrust_policy_ref_id'); + delete_post_meta($post_id, '_ettic_otc_policy_ref_id'); } $valid_categories = ['security', 'privacy', 'compliance', 'operational', 'other']; - $category = sanitize_text_field( wp_unslash( $_POST['opentrust_policy_category'] ?? 'other' ) ); - update_post_meta($post_id, '_opentrust_policy_category', in_array($category, $valid_categories, true) ? $category : 'other'); + $category = sanitize_text_field( wp_unslash( $_POST['ettic_otc_policy_category'] ?? 'other' ) ); + update_post_meta($post_id, '_ettic_otc_policy_category', in_array($category, $valid_categories, true) ? $category : 'other'); - update_post_meta($post_id, '_opentrust_policy_effective_date', sanitize_text_field( wp_unslash( $_POST['opentrust_policy_effective_date'] ?? '' ) )); - update_post_meta($post_id, '_opentrust_policy_review_date', sanitize_text_field( wp_unslash( $_POST['opentrust_policy_review_date'] ?? '' ) )); - update_post_meta($post_id, '_opentrust_policy_sort_order', absint( wp_unslash( $_POST['opentrust_policy_sort_order'] ?? 0 ) )); + update_post_meta($post_id, '_ettic_otc_policy_effective_date', sanitize_text_field( wp_unslash( $_POST['ettic_otc_policy_effective_date'] ?? '' ) )); + update_post_meta($post_id, '_ettic_otc_policy_review_date', sanitize_text_field( wp_unslash( $_POST['ettic_otc_policy_review_date'] ?? '' ) )); + update_post_meta($post_id, '_ettic_otc_policy_sort_order', absint( wp_unslash( $_POST['ettic_otc_policy_sort_order'] ?? 0 ) )); - // Framework citations — repeater array, shape mirrors opentrust_dp_data_items. + // Framework citations — repeater array, shape mirrors ettic_otc_dp_data_items. // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Each element is individually sanitized below. - $raw_citations = wp_unslash( $_POST['opentrust_policy_citations'] ?? [] ); + $raw_citations = wp_unslash( $_POST['ettic_otc_policy_citations'] ?? [] ); $citations = []; if (is_array($raw_citations)) { foreach ($raw_citations as $entry) { @@ -916,37 +916,37 @@ private function save_policy_meta(int $post_id): void { } } if (!empty($citations)) { - update_post_meta($post_id, '_opentrust_policy_citations', $citations); + update_post_meta($post_id, '_ettic_otc_policy_citations', $citations); } else { - delete_post_meta($post_id, '_opentrust_policy_citations'); + delete_post_meta($post_id, '_ettic_otc_policy_citations'); } // PDF attachment — only accept a real attachment the user can read. - $attachment_id = absint( wp_unslash( $_POST['opentrust_policy_attachment_id'] ?? 0 ) ); + $attachment_id = absint( wp_unslash( $_POST['ettic_otc_policy_attachment_id'] ?? 0 ) ); if ($attachment_id > 0 && get_post_type($attachment_id) === 'attachment') { - update_post_meta($post_id, '_opentrust_policy_attachment_id', $attachment_id); + update_post_meta($post_id, '_ettic_otc_policy_attachment_id', $attachment_id); } else { - delete_post_meta($post_id, '_opentrust_policy_attachment_id'); + delete_post_meta($post_id, '_ettic_otc_policy_attachment_id'); } } private function save_sub_meta(int $post_id): void { - if (!isset($_POST['opentrust_sub_nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['opentrust_sub_nonce'] ) ), 'opentrust_save_sub')) { + if (!isset($_POST['ettic_otc_sub_nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['ettic_otc_sub_nonce'] ) ), 'ettic_otc_save_sub')) { return; } if (!current_user_can('edit_post', $post_id)) { return; } - update_post_meta($post_id, '_opentrust_sub_purpose', sanitize_textarea_field( wp_unslash( $_POST['opentrust_sub_purpose'] ?? '' ) )); - update_post_meta($post_id, '_opentrust_sub_data_processed', sanitize_textarea_field( wp_unslash( $_POST['opentrust_sub_data_processed'] ?? '' ) )); - update_post_meta($post_id, '_opentrust_sub_country', sanitize_text_field( wp_unslash( $_POST['opentrust_sub_country'] ?? '' ) )); - update_post_meta($post_id, '_opentrust_sub_website', esc_url_raw( wp_unslash( $_POST['opentrust_sub_website'] ?? '' ) )); - update_post_meta($post_id, '_opentrust_sub_dpa_signed', !empty($_POST['opentrust_sub_dpa_signed'])); + update_post_meta($post_id, '_ettic_otc_sub_purpose', sanitize_textarea_field( wp_unslash( $_POST['ettic_otc_sub_purpose'] ?? '' ) )); + update_post_meta($post_id, '_ettic_otc_sub_data_processed', sanitize_textarea_field( wp_unslash( $_POST['ettic_otc_sub_data_processed'] ?? '' ) )); + update_post_meta($post_id, '_ettic_otc_sub_country', sanitize_text_field( wp_unslash( $_POST['ettic_otc_sub_country'] ?? '' ) )); + update_post_meta($post_id, '_ettic_otc_sub_website', esc_url_raw( wp_unslash( $_POST['ettic_otc_sub_website'] ?? '' ) )); + update_post_meta($post_id, '_ettic_otc_sub_dpa_signed', !empty($_POST['ettic_otc_sub_dpa_signed'])); } private function save_dp_meta(int $post_id): void { - if (!isset($_POST['opentrust_dp_nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['opentrust_dp_nonce'] ) ), 'opentrust_save_dp')) { + if (!isset($_POST['ettic_otc_dp_nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['ettic_otc_dp_nonce'] ) ), 'ettic_otc_save_dp')) { return; } if (!current_user_can('edit_post', $post_id)) { @@ -955,7 +955,7 @@ private function save_dp_meta(int $post_id): void { // Data Items (repeater array). // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Each element is individually sanitized below. - $raw_items = wp_unslash( $_POST['opentrust_dp_data_items'] ?? [] ); + $raw_items = wp_unslash( $_POST['ettic_otc_dp_data_items'] ?? [] ); $data_items = []; if (is_array($raw_items)) { foreach ($raw_items as $item) { @@ -965,22 +965,22 @@ private function save_dp_meta(int $post_id): void { } } } - update_post_meta($post_id, '_opentrust_dp_data_items', $data_items); + update_post_meta($post_id, '_ettic_otc_dp_data_items', $data_items); // Purpose. - update_post_meta($post_id, '_opentrust_dp_purpose', sanitize_textarea_field( wp_unslash( $_POST['opentrust_dp_purpose'] ?? '' ) )); + update_post_meta($post_id, '_ettic_otc_dp_purpose', sanitize_textarea_field( wp_unslash( $_POST['ettic_otc_dp_purpose'] ?? '' ) )); // Legal Basis. $valid_bases = ['consent', 'contract', 'legitimate_interest', 'legal_obligation', 'vital_interest', 'public_interest']; - $basis = sanitize_text_field( wp_unslash( $_POST['opentrust_dp_legal_basis'] ?? '' ) ); - update_post_meta($post_id, '_opentrust_dp_legal_basis', in_array($basis, $valid_bases, true) ? $basis : ''); + $basis = sanitize_text_field( wp_unslash( $_POST['ettic_otc_dp_legal_basis'] ?? '' ) ); + update_post_meta($post_id, '_ettic_otc_dp_legal_basis', in_array($basis, $valid_bases, true) ? $basis : ''); // Retention Period. - update_post_meta($post_id, '_opentrust_dp_retention_period', sanitize_text_field( wp_unslash( $_POST['opentrust_dp_retention_period'] ?? '' ) )); + update_post_meta($post_id, '_ettic_otc_dp_retention_period', sanitize_text_field( wp_unslash( $_POST['ettic_otc_dp_retention_period'] ?? '' ) )); // Shared With (repeater array). // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Each element is individually sanitized below. - $raw_shared = wp_unslash( $_POST['opentrust_dp_shared_with'] ?? [] ); + $raw_shared = wp_unslash( $_POST['ettic_otc_dp_shared_with'] ?? [] ); $shared_items = []; if (is_array($raw_shared)) { foreach ($raw_shared as $entry) { @@ -990,23 +990,23 @@ private function save_dp_meta(int $post_id): void { } } } - update_post_meta($post_id, '_opentrust_dp_shared_with', $shared_items); + update_post_meta($post_id, '_ettic_otc_dp_shared_with', $shared_items); // Sort order. - update_post_meta($post_id, '_opentrust_dp_sort_order', absint( wp_unslash( $_POST['opentrust_dp_sort_order'] ?? 0 ) )); + update_post_meta($post_id, '_ettic_otc_dp_sort_order', absint( wp_unslash( $_POST['ettic_otc_dp_sort_order'] ?? 0 ) )); // Property flags — the AI assistant reports these verbatim. Unchecked // means explicit "No", not "unknown", so we always write the value. - update_post_meta($post_id, '_opentrust_dp_collected', !empty($_POST['opentrust_dp_collected'])); - update_post_meta($post_id, '_opentrust_dp_stored', !empty($_POST['opentrust_dp_stored'])); - update_post_meta($post_id, '_opentrust_dp_shared', !empty($_POST['opentrust_dp_shared'])); - update_post_meta($post_id, '_opentrust_dp_sold', !empty($_POST['opentrust_dp_sold'])); - update_post_meta($post_id, '_opentrust_dp_encrypted', !empty($_POST['opentrust_dp_encrypted'])); + update_post_meta($post_id, '_ettic_otc_dp_collected', !empty($_POST['ettic_otc_dp_collected'])); + update_post_meta($post_id, '_ettic_otc_dp_stored', !empty($_POST['ettic_otc_dp_stored'])); + update_post_meta($post_id, '_ettic_otc_dp_shared', !empty($_POST['ettic_otc_dp_shared'])); + update_post_meta($post_id, '_ettic_otc_dp_sold', !empty($_POST['ettic_otc_dp_sold'])); + update_post_meta($post_id, '_ettic_otc_dp_encrypted', !empty($_POST['ettic_otc_dp_encrypted'])); // Clean up legacy meta keys. - delete_post_meta($post_id, '_opentrust_dp_data_type'); - delete_post_meta($post_id, '_opentrust_dp_collection_method'); - delete_post_meta($post_id, '_opentrust_dp_is_sensitive'); + delete_post_meta($post_id, '_ettic_otc_dp_data_type'); + delete_post_meta($post_id, '_ettic_otc_dp_collection_method'); + delete_post_meta($post_id, '_ettic_otc_dp_is_sensitive'); } // ────────────────────────────────────────────── @@ -1018,19 +1018,19 @@ public function cert_columns(array $columns): array { $new = []; $new['cb'] = $columns['cb']; $new['title'] = $columns['title']; - $new['opentrust_issuing_body'] = __('Issuing Body', 'opentrust'); - $new['opentrust_status'] = __('Status', 'opentrust'); - $new['opentrust_expiry'] = __('Expiry Date', 'opentrust'); + $new['ettic_otc_issuing_body'] = __('Issuing Body', 'opentrust'); + $new['ettic_otc_status'] = __('Status', 'opentrust'); + $new['ettic_otc_expiry'] = __('Expiry Date', 'opentrust'); $new['date'] = $columns['date']; return $new; } public function cert_column_content(string $column, int $post_id): void { match ($column) { - 'opentrust_issuing_body' => print(esc_html(get_post_meta($post_id, '_opentrust_cert_issuing_body', true) ?: '—')), - 'opentrust_status' => (function () use ($post_id): void { - $status = get_post_meta($post_id, '_opentrust_cert_status', true) ?: 'active'; - $type = get_post_meta($post_id, '_opentrust_cert_type', true) ?: 'compliant'; + 'ettic_otc_issuing_body' => print(esc_html(get_post_meta($post_id, '_ettic_otc_cert_issuing_body', true) ?: '—')), + 'ettic_otc_status' => (function () use ($post_id): void { + $status = get_post_meta($post_id, '_ettic_otc_cert_status', true) ?: 'active'; + $type = get_post_meta($post_id, '_ettic_otc_cert_type', true) ?: 'compliant'; $labels = $type === 'compliant' ? Ettic_OTC_Render::cert_aligned_status_labels() : Ettic_OTC_Render::cert_status_labels(); @@ -1047,7 +1047,7 @@ public function cert_column_content(string $column, int $post_id): void { esc_html($labels[$status] ?? '') ); })(), - 'opentrust_expiry' => print(esc_html(get_post_meta($post_id, '_opentrust_cert_expiry_date', true) ?: '—')), + 'ettic_otc_expiry' => print(esc_html(get_post_meta($post_id, '_ettic_otc_cert_expiry_date', true) ?: '—')), default => null, }; } @@ -1057,10 +1057,10 @@ public function policy_columns(array $columns): array { $new = []; $new['cb'] = $columns['cb']; $new['title'] = $columns['title']; - $new['opentrust_ref_id'] = __('ID', 'opentrust'); - $new['opentrust_category'] = __('Category', 'opentrust'); - $new['opentrust_version'] = __('Version', 'opentrust'); - $new['opentrust_pdf'] = __('PDF', 'opentrust'); + $new['ettic_otc_ref_id'] = __('ID', 'opentrust'); + $new['ettic_otc_category'] = __('Category', 'opentrust'); + $new['ettic_otc_version'] = __('Version', 'opentrust'); + $new['ettic_otc_pdf'] = __('PDF', 'opentrust'); $new['date'] = $columns['date']; return $new; } @@ -1068,17 +1068,17 @@ public function policy_columns(array $columns): array { public function policy_column_content(string $column, int $post_id): void { // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped -- Match arms emit either hard-coded HTML or values already passed through esc_html(); PHPCS misreads the IIFE/match-expression syntax. match ($column) { - 'opentrust_ref_id' => (function () use ($post_id): void { - $ref = (string) get_post_meta($post_id, '_opentrust_policy_ref_id', true); + 'ettic_otc_ref_id' => (function () use ($post_id): void { + $ref = (string) get_post_meta($post_id, '_ettic_otc_policy_ref_id', true); if ($ref === '') { print ''; return; } printf('%s', esc_html($ref)); })(), - 'opentrust_category' => print(esc_html(Ettic_OTC_Render::policy_category_labels()[get_post_meta($post_id, '_opentrust_policy_category', true) ?: 'other'] ?? '')), - 'opentrust_version' => printf('v%s', esc_html((string) ((int) get_post_meta($post_id, '_opentrust_version', true) ?: 1))), - 'opentrust_pdf' => print(((int) get_post_meta($post_id, '_opentrust_policy_attachment_id', true)) > 0 ? '' : ''), + 'ettic_otc_category' => print(esc_html(Ettic_OTC_Render::policy_category_labels()[get_post_meta($post_id, '_ettic_otc_policy_category', true) ?: 'other'] ?? '')), + 'ettic_otc_version' => printf('v%s', esc_html((string) ((int) get_post_meta($post_id, '_ettic_otc_version', true) ?: 1))), + 'ettic_otc_pdf' => print(((int) get_post_meta($post_id, '_ettic_otc_policy_attachment_id', true)) > 0 ? '' : ''), default => null, }; // phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped @@ -1089,18 +1089,18 @@ public function sub_columns(array $columns): array { $new = []; $new['cb'] = $columns['cb']; $new['title'] = $columns['title']; - $new['opentrust_purpose'] = __('Purpose', 'opentrust'); - $new['opentrust_country'] = __('Location', 'opentrust'); - $new['opentrust_dpa'] = __('DPA', 'opentrust'); + $new['ettic_otc_purpose'] = __('Purpose', 'opentrust'); + $new['ettic_otc_country'] = __('Location', 'opentrust'); + $new['ettic_otc_dpa'] = __('DPA', 'opentrust'); $new['date'] = $columns['date']; return $new; } public function sub_column_content(string $column, int $post_id): void { match ($column) { - 'opentrust_purpose' => print(esc_html(wp_trim_words(get_post_meta($post_id, '_opentrust_sub_purpose', true) ?: '', 10))), - 'opentrust_country' => print(esc_html(get_post_meta($post_id, '_opentrust_sub_country', true) ?: '—')), - 'opentrust_dpa' => print((bool) get_post_meta($post_id, '_opentrust_sub_dpa_signed', true) ? '' : '—'), + 'ettic_otc_purpose' => print(esc_html(wp_trim_words(get_post_meta($post_id, '_ettic_otc_sub_purpose', true) ?: '', 10))), + 'ettic_otc_country' => print(esc_html(get_post_meta($post_id, '_ettic_otc_sub_country', true) ?: '—')), + 'ettic_otc_dpa' => print((bool) get_post_meta($post_id, '_ettic_otc_sub_dpa_signed', true) ? '' : '—'), default => null, }; } @@ -1110,16 +1110,16 @@ public function dp_columns(array $columns): array { $new = []; $new['cb'] = $columns['cb']; $new['title'] = $columns['title']; - $new['opentrust_dp_items'] = __('Data Items', 'opentrust'); - $new['opentrust_dp_sort'] = __('Order', 'opentrust'); + $new['ettic_otc_dp_items'] = __('Data Items', 'opentrust'); + $new['ettic_otc_dp_sort'] = __('Order', 'opentrust'); $new['date'] = $columns['date']; return $new; } public function dp_column_content(string $column, int $post_id): void { match ($column) { - 'opentrust_dp_items' => print(esc_html((string) count((array) (get_post_meta($post_id, '_opentrust_dp_data_items', true) ?: [])))), - 'opentrust_dp_sort' => print(esc_html((string) ((int) get_post_meta($post_id, '_opentrust_dp_sort_order', true)))), + 'ettic_otc_dp_items' => print(esc_html((string) count((array) (get_post_meta($post_id, '_ettic_otc_dp_data_items', true) ?: [])))), + 'ettic_otc_dp_sort' => print(esc_html((string) ((int) get_post_meta($post_id, '_ettic_otc_dp_sort_order', true)))), default => null, }; } @@ -1127,9 +1127,9 @@ public function dp_column_content(string $column, int $post_id): void { // ── FAQ meta box ── public function render_faq_meta_box(\WP_Post $post): void { - wp_nonce_field('opentrust_save_faq', 'opentrust_faq_nonce'); + wp_nonce_field('ettic_otc_save_faq', 'ettic_otc_faq_nonce'); - $policy_id = (int) get_post_meta($post->ID, '_opentrust_faq_related_policy', true); + $policy_id = (int) get_post_meta($post->ID, '_ettic_otc_faq_related_policy', true); $policies = get_posts([ 'post_type' => self::POLICY, @@ -1140,8 +1140,8 @@ public function render_faq_meta_box(\WP_Post $post): void { ]); ?>
- - @@ -1160,18 +1160,18 @@ public function render_faq_meta_box(\WP_Post $post): void { } private function save_faq_meta(int $post_id): void { - if (!isset($_POST['opentrust_faq_nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['opentrust_faq_nonce'] ) ), 'opentrust_save_faq')) { + if (!isset($_POST['ettic_otc_faq_nonce']) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['ettic_otc_faq_nonce'] ) ), 'ettic_otc_save_faq')) { return; } if (!current_user_can('edit_post', $post_id)) { return; } - $related = absint( wp_unslash( $_POST['opentrust_faq_related_policy'] ?? 0 ) ); + $related = absint( wp_unslash( $_POST['ettic_otc_faq_related_policy'] ?? 0 ) ); if ($related > 0 && get_post_type($related) === self::POLICY) { - update_post_meta($post_id, '_opentrust_faq_related_policy', $related); + update_post_meta($post_id, '_ettic_otc_faq_related_policy', $related); } else { - delete_post_meta($post_id, '_opentrust_faq_related_policy'); + delete_post_meta($post_id, '_ettic_otc_faq_related_policy'); } } @@ -1180,14 +1180,14 @@ public function faq_columns(array $columns): array { $new = []; $new['cb'] = $columns['cb']; $new['title'] = $columns['title']; - $new['opentrust_faq_order'] = __('Order', 'opentrust'); + $new['ettic_otc_faq_order'] = __('Order', 'opentrust'); $new['date'] = $columns['date']; return $new; } public function faq_column_content(string $column, int $post_id): void { match ($column) { - 'opentrust_faq_order' => print(esc_html((string) ((int) (get_post($post_id)->menu_order ?? 0)))), + 'ettic_otc_faq_order' => print(esc_html((string) ((int) (get_post($post_id)->menu_order ?? 0)))), default => null, }; } diff --git a/includes/class-ettic-otc-io.php b/includes/class-ettic-otc-io.php index c650245..bc4950f 100644 --- a/includes/class-ettic-otc-io.php +++ b/includes/class-ettic-otc-io.php @@ -12,8 +12,8 @@ final class Ettic_OTC_IO { public const SCHEMA_VERSION = 1; - public const FORMAT_SETTINGS = 'opentrust-settings'; - public const FORMAT_CONTENT = 'opentrust-content'; + public const FORMAT_SETTINGS = 'ettic-otc-settings'; + public const FORMAT_CONTENT = 'ettic-otc-content'; public const STRATEGY_SKIP = 'skip'; public const STRATEGY_OVERWRITE = 'overwrite'; @@ -22,7 +22,7 @@ final class Ettic_OTC_IO { // Encrypted secrets, per-site salt, and server-controlled flags. Never exported. public const SETTINGS_EXCLUDE = [ 'turnstile_secret_key', - 'opentrust_site_salt', + 'ettic_otc_site_salt', 'ai_enabled', 'ai_provider', // ai_model is paired with ai_provider — exporting it without the provider @@ -38,63 +38,63 @@ final class Ettic_OTC_IO { // Keep in sync with class-ettic-otc-cpt.php save handlers. private const META_KEYS = [ Ettic_OTC_CPT::POLICY => [ - '_opentrust_uuid', - '_opentrust_policy_ref_id', - '_opentrust_policy_category', - '_opentrust_policy_effective_date', - '_opentrust_policy_review_date', - '_opentrust_policy_sort_order', - '_opentrust_policy_citations', - '_opentrust_policy_attachment_id', - '_opentrust_version', - '_opentrust_version_summary', - '_opentrust_policy_chat_summary', - '_opentrust_policy_chat_summary_updated_at', - '_opentrust_policy_chat_summary_origin', + '_ettic_otc_uuid', + '_ettic_otc_policy_ref_id', + '_ettic_otc_policy_category', + '_ettic_otc_policy_effective_date', + '_ettic_otc_policy_review_date', + '_ettic_otc_policy_sort_order', + '_ettic_otc_policy_citations', + '_ettic_otc_policy_attachment_id', + '_ettic_otc_version', + '_ettic_otc_version_summary', + '_ettic_otc_policy_chat_summary', + '_ettic_otc_policy_chat_summary_updated_at', + '_ettic_otc_policy_chat_summary_origin', ], Ettic_OTC_CPT::CERTIFICATION => [ - '_opentrust_uuid', - '_opentrust_cert_type', - '_opentrust_cert_status', - '_opentrust_cert_issuing_body', - '_opentrust_cert_issue_date', - '_opentrust_cert_expiry_date', - '_opentrust_cert_badge_id', - '_opentrust_cert_artifact_id', - '_opentrust_cert_description', + '_ettic_otc_uuid', + '_ettic_otc_cert_type', + '_ettic_otc_cert_status', + '_ettic_otc_cert_issuing_body', + '_ettic_otc_cert_issue_date', + '_ettic_otc_cert_expiry_date', + '_ettic_otc_cert_badge_id', + '_ettic_otc_cert_artifact_id', + '_ettic_otc_cert_description', ], Ettic_OTC_CPT::SUBPROCESSOR => [ - '_opentrust_uuid', - '_opentrust_sub_purpose', - '_opentrust_sub_data_processed', - '_opentrust_sub_country', - '_opentrust_sub_website', - '_opentrust_sub_dpa_signed', + '_ettic_otc_uuid', + '_ettic_otc_sub_purpose', + '_ettic_otc_sub_data_processed', + '_ettic_otc_sub_country', + '_ettic_otc_sub_website', + '_ettic_otc_sub_dpa_signed', ], Ettic_OTC_CPT::DATA_PRACTICE => [ - '_opentrust_uuid', - '_opentrust_dp_data_items', - '_opentrust_dp_purpose', - '_opentrust_dp_legal_basis', - '_opentrust_dp_retention_period', - '_opentrust_dp_shared_with', - '_opentrust_dp_sort_order', - '_opentrust_dp_collected', - '_opentrust_dp_stored', - '_opentrust_dp_shared', - '_opentrust_dp_sold', - '_opentrust_dp_encrypted', + '_ettic_otc_uuid', + '_ettic_otc_dp_data_items', + '_ettic_otc_dp_purpose', + '_ettic_otc_dp_legal_basis', + '_ettic_otc_dp_retention_period', + '_ettic_otc_dp_shared_with', + '_ettic_otc_dp_sort_order', + '_ettic_otc_dp_collected', + '_ettic_otc_dp_stored', + '_ettic_otc_dp_shared', + '_ettic_otc_dp_sold', + '_ettic_otc_dp_encrypted', ], Ettic_OTC_CPT::FAQ => [ - '_opentrust_uuid', - '_opentrust_faq_related_policy', + '_ettic_otc_uuid', + '_ettic_otc_faq_related_policy', ], ]; // Meta keys whose value is an attachment ID; serialized as __media_ref. private const ATTACHMENT_META_KEYS = [ - Ettic_OTC_CPT::POLICY => ['_opentrust_policy_attachment_id'], - Ettic_OTC_CPT::CERTIFICATION => ['_opentrust_cert_badge_id', '_opentrust_cert_artifact_id'], + Ettic_OTC_CPT::POLICY => ['_ettic_otc_policy_attachment_id'], + Ettic_OTC_CPT::CERTIFICATION => ['_ettic_otc_cert_badge_id', '_ettic_otc_cert_artifact_id'], Ettic_OTC_CPT::SUBPROCESSOR => [], Ettic_OTC_CPT::DATA_PRACTICE => [], Ettic_OTC_CPT::FAQ => [], @@ -103,7 +103,7 @@ final class Ettic_OTC_IO { // meta_key => target_cpt_slug. Cross-CPT refs serialized as __post_ref. private const POST_REF_META_KEYS = [ Ettic_OTC_CPT::FAQ => [ - '_opentrust_faq_related_policy' => Ettic_OTC_CPT::POLICY, + '_ettic_otc_faq_related_policy' => Ettic_OTC_CPT::POLICY, ], ]; @@ -133,7 +133,7 @@ public static function build_settings_manifest(bool $include_media = true): arra return [ 'format' => self::FORMAT_SETTINGS, 'schema' => self::SCHEMA_VERSION, - 'opentrust_version' => ETTIC_OTC_VERSION, + 'ettic_otc_version' => ETTIC_OTC_VERSION, 'db_version' => ETTIC_OTC_DB_VERSION, 'exported_at' => gmdate('c'), 'site_url' => home_url('/'), @@ -177,7 +177,7 @@ public static function build_content_manifest(array $selection, bool $include_me return [ 'format' => self::FORMAT_CONTENT, 'schema' => self::SCHEMA_VERSION, - 'opentrust_version' => ETTIC_OTC_VERSION, + 'ettic_otc_version' => ETTIC_OTC_VERSION, 'db_version' => ETTIC_OTC_DB_VERSION, 'exported_at' => gmdate('c'), 'site_url' => home_url('/'), @@ -249,13 +249,13 @@ public static function validate_manifest(array $manifest): array { ); } - $their_major = (int) explode('.', (string) ($manifest['opentrust_version'] ?? '0.0.0'))[0]; + $their_major = (int) explode('.', (string) ($manifest['ettic_otc_version'] ?? '0.0.0'))[0]; $our_major = (int) explode('.', ETTIC_OTC_VERSION)[0]; if ($their_major !== $our_major) { $errors[] = sprintf( /* translators: %1$s: their version, %2$s: our version */ __('Plugin major version mismatch (export: %1$s, this site: %2$s).', 'opentrust'), - (string) ($manifest['opentrust_version'] ?? '?'), + (string) ($manifest['ettic_otc_version'] ?? '?'), ETTIC_OTC_VERSION ); } @@ -375,11 +375,11 @@ public static function apply_settings_import(array $manifest, string $zip_path): $merged[$k] = $current[$k] ?? ''; } - update_option('opentrust_settings', $merged, false); + update_option('ettic_otc_settings', $merged, false); // Slug change → flush rewrites on next admin load. if (isset($imported['endpoint_slug']) && $imported['endpoint_slug'] !== ($current['endpoint_slug'] ?? '')) { - set_transient('opentrust_flush_rewrite', true); + set_transient('ettic_otc_flush_rewrite', true); } Ettic_OTC::instance()->invalidate_cache(); @@ -416,16 +416,11 @@ public static function read_zip(string $zip_path): array { // ────────────────────────────────────────────── /** - * Rewrite v1.0.x CPT slugs (ot_*) in an inbound manifest to the v1.1+ - * slugs (opentr_*). Touches top-level record keys only — record bodies - * carry __post_ref values as UUIDs (not slugs) and resolve fine once the - * outer key is corrected. - * - * @deprecated 1.1.0 Drop in 2.0.0. The major-version mismatch check in - * validate_manifest() already hard-rejects 1.x archives on a - * 2.x destination, so this remap becomes redundant. Also - * remove the two call sites in preview_import() and - * apply_content_import(). + * Rewrite legacy CPT slugs (v1.0.x `ot_*`, v1.1.x `opentr_*`) in an + * inbound manifest to the current `eotc_*` slugs. Touches top-level + * record keys only — record bodies carry __post_ref values as UUIDs + * (not slugs) and resolve fine once the outer key is corrected. Phase 8 + * extends Ettic_OTC_CPT::LEGACY_MAP with the v1.1.x entries. */ private static function remap_legacy_cpt_keys(array $manifest): array { if (empty($manifest['records']) || !is_array($manifest['records'])) { @@ -441,7 +436,7 @@ private static function remap_legacy_cpt_keys(array $manifest): array { /** * Rewrite legacy `_ot_*` postmeta keys in an inbound manifest's record - * bodies to the v1.1.1+ `_opentrust_*` keys. Pre-1.1.1 exports carry the + * bodies to the v1.1.1+ `_ettic_otc_*` keys. Pre-1.1.1 exports carry the * short prefix; without this remap their meta would be written under the * old key names and read back as empty. * @@ -509,7 +504,7 @@ private static function record_for_post(int $post_id, bool $include_media, array foreach (self::POST_REF_META_KEYS[$cpt] ?? [] as $meta_key => $_target_cpt) { $ref_id = (int) ($meta_out[$meta_key] ?? 0); if ($ref_id > 0) { - $ref_uuid = (string) get_post_meta($ref_id, '_opentrust_uuid', true); + $ref_uuid = (string) get_post_meta($ref_id, '_ettic_otc_uuid', true); if ($ref_uuid !== '') { $meta_out[$meta_key] = ['__post_ref' => $ref_uuid]; } else { @@ -519,7 +514,7 @@ private static function record_for_post(int $post_id, bool $include_media, array } return [ - 'uuid' => $meta_out['_opentrust_uuid'] ?? null, + 'uuid' => $meta_out['_ettic_otc_uuid'] ?? null, 'slug' => $post->post_name, 'title' => $post->post_title, 'content' => $post->post_content, @@ -541,8 +536,8 @@ private static function collect_attachment(int $att_id, array &$media): ?string } // Stamp the source so a same-site re-import dedupes by hash instead // of re-uploading (and tripping WP's MIME allowlist on SVG, etc.). - if (!get_post_meta($att_id, '_opentrust_import_sha256', true)) { - update_post_meta($att_id, '_opentrust_import_sha256', $hash); + if (!get_post_meta($att_id, '_ettic_otc_import_sha256', true)) { + update_post_meta($att_id, '_ettic_otc_import_sha256', $hash); } $att = get_post($att_id); $ext = pathinfo($path, PATHINFO_EXTENSION); @@ -572,7 +567,7 @@ private static function find_existing_post(string $cpt, array $rec): int { 'posts_per_page' => 1, 'fields' => 'ids', 'meta_query' => [ - ['key' => '_opentrust_uuid', 'value' => $uuid], + ['key' => '_ettic_otc_uuid', 'value' => $uuid], ], ]); if (!empty($hits)) return (int) $hits[0]; @@ -655,8 +650,8 @@ private static function upsert_record(string $cpt, array $rec, string $strategy, } // Fresh UUID on create_new so we don't collide with the existing post. - if (empty($meta['_opentrust_uuid']) || $strategy === self::STRATEGY_CREATE_NEW) { - $meta['_opentrust_uuid'] = wp_generate_uuid4(); + if (empty($meta['_ettic_otc_uuid']) || $strategy === self::STRATEGY_CREATE_NEW) { + $meta['_ettic_otc_uuid'] = wp_generate_uuid4(); } foreach ($meta as $key => $val) { @@ -760,7 +755,7 @@ private static function sideload_bundled_media(array $media, string $zip_path, a update_post_meta($att_id, '_wp_attachment_image_alt', (string) $entry['alt']); } - update_post_meta($att_id, '_opentrust_import_sha256', $hash); + update_post_meta($att_id, '_ettic_otc_import_sha256', $hash); $map[$hash] = $att_id; } @@ -775,7 +770,7 @@ private static function find_attachment_by_hash(string $hash): int { 'posts_per_page' => 1, 'fields' => 'ids', 'meta_query' => [ - ['key' => '_opentrust_import_sha256', 'value' => $hash], + ['key' => '_ettic_otc_import_sha256', 'value' => $hash], ], ]); return !empty($hits) ? (int) $hits[0] : 0; diff --git a/includes/class-ettic-otc-render.php b/includes/class-ettic-otc-render.php index 3cc529d..393a726 100644 --- a/includes/class-ettic-otc-render.php +++ b/includes/class-ettic-otc-render.php @@ -79,7 +79,7 @@ private function render_chat_page(): void { */ private function handle_chat_noscript_post(array $settings): array { $nonce = isset($_POST['_wpnonce']) ? sanitize_text_field((string) wp_unslash($_POST['_wpnonce'])) : ''; - if (!wp_verify_nonce($nonce, 'opentrust_chat_noscript')) { + if (!wp_verify_nonce($nonce, 'ettic_otc_chat_noscript')) { return ['error' => __('Session expired. Please reload the page and try again.', 'opentrust')]; } @@ -178,7 +178,7 @@ private function render_trust_center(): void { // ────────────────────────────────────────────── private function render_policy_single(): void { - $slug = sanitize_title(get_query_var('opentrust_policy_slug', '')); + $slug = sanitize_title(get_query_var('ettic_otc_policy_slug', '')); $policy = $this->find_policy_by_slug($slug); if (!$policy) { @@ -191,7 +191,7 @@ private function render_policy_single(): void { $ot_data['current_policy'] = $policy; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Core WordPress filter $ot_data['policy_content'] = apply_filters('the_content', $policy->post_content); - $ot_data['policy_version'] = (int) get_post_meta($policy->ID, '_opentrust_version', true) ?: 1; + $ot_data['policy_version'] = (int) get_post_meta($policy->ID, '_ettic_otc_version', true) ?: 1; $ot_data['policy_meta'] = $this->get_policy_meta($policy->ID); $ot_data['policy_versions'] = $this->get_policy_versions($policy); $ot_data['is_pending'] = $this->is_future_dated($policy); @@ -206,8 +206,8 @@ private function render_policy_single(): void { // ────────────────────────────────────────────── private function render_policy_version(): void { - $slug = sanitize_title(get_query_var('opentrust_policy_slug', '')); - $version = (int) get_query_var('opentrust_version', '0'); + $slug = sanitize_title(get_query_var('ettic_otc_policy_slug', '')); + $version = (int) get_query_var('ettic_otc_version', '0'); $policy = $this->find_policy_by_slug($slug); if (!$policy || $version < 1) { @@ -216,7 +216,7 @@ private function render_policy_version(): void { } // Current version — redirect to canonical. - $current_version = (int) get_post_meta($policy->ID, '_opentrust_version', true) ?: 1; + $current_version = (int) get_post_meta($policy->ID, '_ettic_otc_version', true) ?: 1; if ($version === $current_version) { $settings = Ettic_OTC::get_settings(); $base = home_url('/' . $settings['endpoint_slug'] . '/policy/' . $policy->post_name . '/'); @@ -228,7 +228,7 @@ private function render_policy_version(): void { $revisions = wp_get_post_revisions($policy->ID, ['order' => 'ASC']); $target = null; foreach ($revisions as $rev) { - if ((int) get_post_meta($rev->ID, '_opentrust_version', true) === $version) { + if ((int) get_post_meta($rev->ID, '_ettic_otc_version', true) === $version) { $target = $rev; break; } @@ -353,7 +353,7 @@ public function gather_data(array $settings): array { * Whether a policy's effective date is in the future. */ private function is_future_dated(\WP_Post $policy): bool { - $effective_date = get_post_meta($policy->ID, '_opentrust_policy_effective_date', true); + $effective_date = get_post_meta($policy->ID, '_ettic_otc_policy_effective_date', true); if (!$effective_date) { return false; } @@ -372,12 +372,12 @@ private function is_future_dated(\WP_Post $policy): bool { private function get_policy_versions(\WP_Post $policy): array { $settings = Ettic_OTC::get_settings(); $endpoint = $settings['endpoint_slug'] ?? Ettic_OTC::DEFAULT_ENDPOINT_SLUG; - $current_version = (int) get_post_meta($policy->ID, '_opentrust_version', true) ?: 1; + $current_version = (int) get_post_meta($policy->ID, '_ettic_otc_version', true) ?: 1; $current_url = home_url('/' . $endpoint . '/policy/' . $policy->post_name . '/'); // Start with the current version. $date_fmt = get_option('date_format'); - $current_eff = get_post_meta($policy->ID, '_opentrust_policy_effective_date', true); + $current_eff = get_post_meta($policy->ID, '_ettic_otc_policy_effective_date', true); $versions = []; $versions[] = [ 'version' => $current_version, @@ -386,7 +386,7 @@ private function get_policy_versions(\WP_Post $policy): array { : wp_date($date_fmt, strtotime($policy->post_modified)), 'url' => $current_url, 'current' => true, - 'summary' => get_post_meta($policy->ID, '_opentrust_version_summary', true) ?: '', + 'summary' => get_post_meta($policy->ID, '_ettic_otc_version_summary', true) ?: '', ]; // Add past versions from revisions. @@ -397,13 +397,13 @@ private function get_policy_versions(\WP_Post $policy): array { $seen = [$current_version => true]; foreach ($revisions as $rev) { - $rev_version = (int) get_post_meta($rev->ID, '_opentrust_version', true); + $rev_version = (int) get_post_meta($rev->ID, '_ettic_otc_version', true); if (!$rev_version || isset($seen[$rev_version])) { continue; } $seen[$rev_version] = true; - $rev_eff = get_post_meta($rev->ID, '_opentrust_policy_effective_date', true); + $rev_eff = get_post_meta($rev->ID, '_ettic_otc_policy_effective_date', true); $versions[] = [ 'version' => $rev_version, 'date' => $rev_eff @@ -411,7 +411,7 @@ private function get_policy_versions(\WP_Post $policy): array { : wp_date($date_fmt, strtotime($rev->post_modified)), 'url' => home_url('/' . $endpoint . '/policy/' . $policy->post_name . '/version/' . $rev_version . '/'), 'current' => false, - 'summary' => get_post_meta($rev->ID, '_opentrust_version_summary', true) ?: '', + 'summary' => get_post_meta($rev->ID, '_ettic_otc_version_summary', true) ?: '', ]; } @@ -494,11 +494,11 @@ private function find_policy_by_slug(string $slug): ?\WP_Post { private function get_policy_meta(int $post_id): array { $repo = Ettic_OTC_Repository::instance(); return [ - 'ref_id' => (string) (get_post_meta($post_id, '_opentrust_policy_ref_id', true) ?: ''), - 'category' => get_post_meta($post_id, '_opentrust_policy_category', true) ?: 'other', - 'citations' => $repo->normalize_citations(get_post_meta($post_id, '_opentrust_policy_citations', true)), - 'effective_date' => get_post_meta($post_id, '_opentrust_policy_effective_date', true) ?: '', - 'review_date' => get_post_meta($post_id, '_opentrust_policy_review_date', true) ?: '', + 'ref_id' => (string) (get_post_meta($post_id, '_ettic_otc_policy_ref_id', true) ?: ''), + 'category' => get_post_meta($post_id, '_ettic_otc_policy_category', true) ?: 'other', + 'citations' => $repo->normalize_citations(get_post_meta($post_id, '_ettic_otc_policy_citations', true)), + 'effective_date' => get_post_meta($post_id, '_ettic_otc_policy_effective_date', true) ?: '', + 'review_date' => get_post_meta($post_id, '_ettic_otc_policy_review_date', true) ?: '', 'attachment' => $repo->resolve_policy_attachment($post_id), ]; } diff --git a/includes/class-ettic-otc-repository.php b/includes/class-ettic-otc-repository.php index 974d9db..fdaba59 100644 --- a/includes/class-ettic-otc-repository.php +++ b/includes/class-ettic-otc-repository.php @@ -16,7 +16,7 @@ * the public page is also hidden from the AI's corpus index. * * Caching: each fetcher is memoized in a locale-scoped transient bumped by - * opentrust_cache_version. Returns are plain projected arrays. + * ettic_otc_cache_version. Returns are plain projected arrays. */ declare(strict_types=1); @@ -51,18 +51,18 @@ public function fetch_certifications(): array { 'order' => 'ASC', ], static function (WP_Post $post): array { - $badge_id = (int) get_post_meta($post->ID, '_opentrust_cert_badge_id', true); - $artifact_id = (int) get_post_meta($post->ID, '_opentrust_cert_artifact_id', true); + $badge_id = (int) get_post_meta($post->ID, '_ettic_otc_cert_badge_id', true); + $artifact_id = (int) get_post_meta($post->ID, '_ettic_otc_cert_artifact_id', true); return [ 'id' => $post->ID, 'title' => $post->post_title, - 'type' => get_post_meta($post->ID, '_opentrust_cert_type', true) ?: 'compliant', - 'issuing_body' => get_post_meta($post->ID, '_opentrust_cert_issuing_body', true) ?: '', - 'status' => get_post_meta($post->ID, '_opentrust_cert_status', true) ?: 'active', - 'issue_date' => get_post_meta($post->ID, '_opentrust_cert_issue_date', true) ?: '', - 'expiry_date' => get_post_meta($post->ID, '_opentrust_cert_expiry_date', true) ?: '', + 'type' => get_post_meta($post->ID, '_ettic_otc_cert_type', true) ?: 'compliant', + 'issuing_body' => get_post_meta($post->ID, '_ettic_otc_cert_issuing_body', true) ?: '', + 'status' => get_post_meta($post->ID, '_ettic_otc_cert_status', true) ?: 'active', + 'issue_date' => get_post_meta($post->ID, '_ettic_otc_cert_issue_date', true) ?: '', + 'expiry_date' => get_post_meta($post->ID, '_ettic_otc_cert_expiry_date', true) ?: '', 'badge_url' => $badge_id ? (wp_get_attachment_image_url($badge_id, 'thumbnail') ?: '') : '', - 'description' => get_post_meta($post->ID, '_opentrust_cert_description', true) ?: '', + 'description' => get_post_meta($post->ID, '_ettic_otc_cert_description', true) ?: '', 'artifact_url' => $artifact_id ? (wp_get_attachment_url($artifact_id) ?: '') : '', ]; } @@ -80,23 +80,23 @@ public function fetch_policies(): array { 'posts_per_page' => -1, 'post_status' => 'publish', 'orderby' => 'meta_value_num title', - 'meta_key' => '_opentrust_policy_sort_order', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Transient-cached; <100 posts + 'meta_key' => '_ettic_otc_policy_sort_order', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Transient-cached; <100 posts 'order' => 'ASC', ], function (WP_Post $post): array { - $eff = get_post_meta($post->ID, '_opentrust_policy_effective_date', true) ?: ''; + $eff = get_post_meta($post->ID, '_ettic_otc_policy_effective_date', true) ?: ''; $attachment = $this->resolve_policy_attachment($post->ID); return [ 'id' => $post->ID, 'title' => $post->post_title, 'slug' => $post->post_name, 'excerpt' => $post->post_excerpt ?: wp_trim_words($post->post_content, 30), - 'version' => (int) get_post_meta($post->ID, '_opentrust_version', true) ?: 1, - 'ref_id' => (string) (get_post_meta($post->ID, '_opentrust_policy_ref_id', true) ?: ''), - 'category' => get_post_meta($post->ID, '_opentrust_policy_category', true) ?: 'other', - 'citations' => $this->normalize_citations(get_post_meta($post->ID, '_opentrust_policy_citations', true)), + 'version' => (int) get_post_meta($post->ID, '_ettic_otc_version', true) ?: 1, + 'ref_id' => (string) (get_post_meta($post->ID, '_ettic_otc_policy_ref_id', true) ?: ''), + 'category' => get_post_meta($post->ID, '_ettic_otc_policy_category', true) ?: 'other', + 'citations' => $this->normalize_citations(get_post_meta($post->ID, '_ettic_otc_policy_citations', true)), 'effective_date' => $eff, - 'review_date' => get_post_meta($post->ID, '_opentrust_policy_review_date', true) ?: '', + 'review_date' => get_post_meta($post->ID, '_ettic_otc_policy_review_date', true) ?: '', 'attachment' => $attachment, 'last_modified' => $post->post_modified, 'is_pending' => $eff && strtotime($eff) > time(), @@ -121,11 +121,11 @@ public function fetch_subprocessors(): array { static fn(WP_Post $post): array => [ 'id' => $post->ID, 'name' => $post->post_title, - 'purpose' => get_post_meta($post->ID, '_opentrust_sub_purpose', true) ?: '', - 'data_processed' => get_post_meta($post->ID, '_opentrust_sub_data_processed', true) ?: '', - 'country' => get_post_meta($post->ID, '_opentrust_sub_country', true) ?: '', - 'website' => get_post_meta($post->ID, '_opentrust_sub_website', true) ?: '', - 'dpa_signed' => (bool) get_post_meta($post->ID, '_opentrust_sub_dpa_signed', true), + 'purpose' => get_post_meta($post->ID, '_ettic_otc_sub_purpose', true) ?: '', + 'data_processed' => get_post_meta($post->ID, '_ettic_otc_sub_data_processed', true) ?: '', + 'country' => get_post_meta($post->ID, '_ettic_otc_sub_country', true) ?: '', + 'website' => get_post_meta($post->ID, '_ettic_otc_sub_website', true) ?: '', + 'dpa_signed' => (bool) get_post_meta($post->ID, '_ettic_otc_sub_dpa_signed', true), ] ); } @@ -141,25 +141,25 @@ public function fetch_data_practices(): array { 'posts_per_page' => -1, 'post_status' => 'publish', 'orderby' => 'meta_value_num title', - 'meta_key' => '_opentrust_dp_sort_order', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Transient-cached; <100 posts + 'meta_key' => '_ettic_otc_dp_sort_order', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Transient-cached; <100 posts 'order' => 'ASC', ], static function (WP_Post $post): array { - $data_items = get_post_meta($post->ID, '_opentrust_dp_data_items', true); - $shared = get_post_meta($post->ID, '_opentrust_dp_shared_with', true); + $data_items = get_post_meta($post->ID, '_ettic_otc_dp_data_items', true); + $shared = get_post_meta($post->ID, '_ettic_otc_dp_shared_with', true); return [ 'id' => $post->ID, 'title' => $post->post_title, 'data_items' => is_array($data_items) ? $data_items : [], - 'purpose' => get_post_meta($post->ID, '_opentrust_dp_purpose', true) ?: '', - 'legal_basis' => get_post_meta($post->ID, '_opentrust_dp_legal_basis', true) ?: '', - 'retention_period' => get_post_meta($post->ID, '_opentrust_dp_retention_period', true) ?: '', + 'purpose' => get_post_meta($post->ID, '_ettic_otc_dp_purpose', true) ?: '', + 'legal_basis' => get_post_meta($post->ID, '_ettic_otc_dp_legal_basis', true) ?: '', + 'retention_period' => get_post_meta($post->ID, '_ettic_otc_dp_retention_period', true) ?: '', 'shared_with' => is_array($shared) ? $shared : [], - 'prop_collected' => (bool) get_post_meta($post->ID, '_opentrust_dp_collected', true), - 'prop_stored' => (bool) get_post_meta($post->ID, '_opentrust_dp_stored', true), - 'prop_shared' => (bool) get_post_meta($post->ID, '_opentrust_dp_shared', true), - 'prop_sold' => (bool) get_post_meta($post->ID, '_opentrust_dp_sold', true), - 'prop_encrypted' => (bool) get_post_meta($post->ID, '_opentrust_dp_encrypted', true), + 'prop_collected' => (bool) get_post_meta($post->ID, '_ettic_otc_dp_collected', true), + 'prop_stored' => (bool) get_post_meta($post->ID, '_ettic_otc_dp_stored', true), + 'prop_shared' => (bool) get_post_meta($post->ID, '_ettic_otc_dp_shared', true), + 'prop_sold' => (bool) get_post_meta($post->ID, '_ettic_otc_dp_sold', true), + 'prop_encrypted' => (bool) get_post_meta($post->ID, '_ettic_otc_dp_encrypted', true), ]; } ); @@ -180,7 +180,7 @@ public function fetch_faqs(): array { 'orderby' => ['menu_order' => 'ASC', 'title' => 'ASC'], ], static function (WP_Post $post) use ($endpoint): array { - $related_id = (int) get_post_meta($post->ID, '_opentrust_faq_related_policy', true); + $related_id = (int) get_post_meta($post->ID, '_ettic_otc_faq_related_policy', true); $related_url = ''; $related_title = ''; if ($related_id && get_post_status($related_id) === 'publish') { @@ -252,17 +252,17 @@ public function section_last_updated(string $post_type): string { /** * Build a locale-and-version-scoped transient key. The locale suffix keeps * WPML/Polylang variants in separate buckets; the version counter - * (opentrust_cache_version, bumped by Ettic_OTC::invalidate_cache) lets a + * (ettic_otc_cache_version, bumped by Ettic_OTC::invalidate_cache) lets a * single option flip bust every cached locale at once. */ private function cache_key(string $bucket): string { - $version = (int) get_option('opentrust_cache_version', 1); - return 'opentrust_' . $bucket . '_' . sanitize_key(determine_locale()) . '_v' . $version; + $version = (int) get_option('ettic_otc_cache_version', 1); + return 'ettic_otc_' . $bucket . '_' . sanitize_key(determine_locale()) . '_v' . $version; } /** * Shared transient + WP_Query plumbing for the per-CPT fetchers. Memoized - * for HOUR_IN_SECONDS and invalidated globally via opentrust_cache_version. + * for HOUR_IN_SECONDS and invalidated globally via ettic_otc_cache_version. * * @param array $query_args * @param callable(WP_Post):array $mapper @@ -313,7 +313,7 @@ public function normalize_citations($raw): array { * @return array{url:string,filename:string,size_bytes:int,size_human:string}|null */ public function resolve_policy_attachment(int $post_id): ?array { - $attachment_id = (int) get_post_meta($post_id, '_opentrust_policy_attachment_id', true); + $attachment_id = (int) get_post_meta($post_id, '_ettic_otc_policy_attachment_id', true); if ($attachment_id <= 0 || get_post_type($attachment_id) !== 'attachment') { return null; } diff --git a/includes/class-ettic-otc-version.php b/includes/class-ettic-otc-version.php index f5380c7..8bad52c 100644 --- a/includes/class-ettic-otc-version.php +++ b/includes/class-ettic-otc-version.php @@ -37,7 +37,7 @@ private function __construct() { * with the OLD version so it's preserved in history. */ public static function bump_version(int $post_id, string $change_summary = ''): void { - $current_version = (int) get_post_meta($post_id, '_opentrust_version', true) ?: 1; + $current_version = (int) get_post_meta($post_id, '_ettic_otc_version', true) ?: 1; $new_version = $current_version + 1; // Find an untagged revision that holds the OLD content (pre-update). @@ -51,7 +51,7 @@ public static function bump_version(int $post_id, string $change_summary = ''): if ($revisions && $post) { foreach ($revisions as $rev) { - $existing = get_post_meta($rev->ID, '_opentrust_version', true); + $existing = get_post_meta($rev->ID, '_ettic_otc_version', true); if (!empty($existing) && (int) $existing > 0) { continue; // already tagged, skip } @@ -66,16 +66,16 @@ public static function bump_version(int $post_id, string $change_summary = ''): // phpcs:disable WordPress.DB.DirectDatabaseQuery, WordPress.DB.SlowDBQuery -- Admin-only postmeta operations on revisions $wpdb->delete($wpdb->postmeta, [ 'post_id' => $rev->ID, - 'meta_key' => '_opentrust_version', + 'meta_key' => '_ettic_otc_version', ]); $wpdb->insert($wpdb->postmeta, [ 'post_id' => $rev->ID, - 'meta_key' => '_opentrust_version', + 'meta_key' => '_ettic_otc_version', 'meta_value' => (string) $current_version, ]); // Copy old version's summary and effective date to the revision. - foreach (['_opentrust_version_summary', '_opentrust_policy_effective_date'] as $meta_key) { + foreach (['_ettic_otc_version_summary', '_ettic_otc_policy_effective_date'] as $meta_key) { $old_val = get_post_meta($post_id, $meta_key, true); if ($old_val) { $wpdb->delete($wpdb->postmeta, [ @@ -97,13 +97,13 @@ public static function bump_version(int $post_id, string $change_summary = ''): } // Bump the main post to the new version. - update_post_meta($post_id, '_opentrust_version', $new_version); + update_post_meta($post_id, '_ettic_otc_version', $new_version); // Store change summary for this version. if ($change_summary !== '') { - update_post_meta($post_id, '_opentrust_version_summary', $change_summary); + update_post_meta($post_id, '_ettic_otc_version_summary', $change_summary); } else { - delete_post_meta($post_id, '_opentrust_version_summary'); + delete_post_meta($post_id, '_ettic_otc_version_summary'); } } @@ -111,9 +111,9 @@ public static function bump_version(int $post_id, string $change_summary = ''): * Ensure a first-publish post gets v1. */ public static function ensure_initial_version(int $post_id): void { - $version = get_post_meta($post_id, '_opentrust_version', true); + $version = get_post_meta($post_id, '_ettic_otc_version', true); if (!$version) { - update_post_meta($post_id, '_opentrust_version', 1); + update_post_meta($post_id, '_ettic_otc_version', 1); } } @@ -123,7 +123,7 @@ public static function ensure_initial_version(int $post_id): void { public function add_version_history_meta_box(): void { add_meta_box( - 'opentrust_version_history', + 'ettic_otc_version_history', __('Version History', 'opentrust'), [$this, 'render_version_history'], Ettic_OTC_CPT::POLICY, @@ -133,7 +133,7 @@ public function add_version_history_meta_box(): void { } public function render_version_history(\WP_Post $post): void { - $current_version = (int) get_post_meta($post->ID, '_opentrust_version', true) ?: 1; + $current_version = (int) get_post_meta($post->ID, '_ettic_otc_version', true) ?: 1; $revisions = wp_get_post_revisions($post->ID, [ 'orderby' => 'ID', 'order' => 'DESC', @@ -169,7 +169,7 @@ public function render_version_history(\WP_Post $post): void { ID, '_opentrust_version', true); + $rev_version = (int) get_post_meta($rev->ID, '_ettic_otc_version', true); if (!$rev_version) continue; if ($rev_version === $current_version) continue; diff --git a/includes/class-ettic-otc.php b/includes/class-ettic-otc.php index 43960dd..382eb3b 100644 --- a/includes/class-ettic-otc.php +++ b/includes/class-ettic-otc.php @@ -90,7 +90,7 @@ public static function defaults(): array { // on first access. Empty here so a fresh install starts in the // "needs lazy generation" state; once written, sanitize_settings // carries it forward byte-for-byte. - 'opentrust_site_salt' => '', + 'ettic_otc_site_salt' => '', // ── AI chat (OTC) ────────────────────────── 'ai_enabled' => false, @@ -124,7 +124,7 @@ public static function defaults(): array { } public static function get_settings(): array { - $saved = get_option('opentrust_settings', []); + $saved = get_option('ettic_otc_settings', []); return wp_parse_args($saved, self::defaults()); } @@ -138,38 +138,38 @@ public static function add_rewrite_rules(): void { add_rewrite_rule( '^' . preg_quote($slug, '/') . '/?$', - 'index.php?opentrust=main', + 'index.php?ettic_otc=main', 'top' ); add_rewrite_rule( '^' . preg_quote($slug, '/') . '/policy/([^/]+)/?$', - 'index.php?opentrust=policy&opentrust_policy_slug=$matches[1]', + 'index.php?ettic_otc=policy&ettic_otc_policy_slug=$matches[1]', 'top' ); add_rewrite_rule( '^' . preg_quote($slug, '/') . '/policy/([^/]+)/version/([0-9]+)/?$', - 'index.php?opentrust=policy_version&opentrust_policy_slug=$matches[1]&opentrust_version=$matches[2]', + 'index.php?ettic_otc=policy_version&ettic_otc_policy_slug=$matches[1]&ettic_otc_version=$matches[2]', 'top' ); // AI chat (OTC). add_rewrite_rule( '^' . preg_quote($slug, '/') . '/ask/?$', - 'index.php?opentrust=ask', + 'index.php?ettic_otc=ask', 'top' ); } public function register_query_vars(array $vars): array { - $vars[] = 'opentrust'; - $vars[] = 'opentrust_policy_slug'; - $vars[] = 'opentrust_version'; + $vars[] = 'ettic_otc'; + $vars[] = 'ettic_otc_policy_slug'; + $vars[] = 'ettic_otc_version'; return $vars; } public function maybe_flush_rewrites(): void { - if (get_transient('opentrust_flush_rewrite')) { - delete_transient('opentrust_flush_rewrite'); + if (get_transient('ettic_otc_flush_rewrite')) { + delete_transient('ettic_otc_flush_rewrite'); flush_rewrite_rules(); } } @@ -179,7 +179,7 @@ public function maybe_flush_rewrites(): void { // ────────────────────────────────────────────── public function maybe_render_trust_center(): void { - $page = get_query_var('opentrust'); + $page = get_query_var('ettic_otc'); if (!$page) { return; } @@ -198,8 +198,8 @@ public function invalidate_cache(): void { // this version in every key, so every cached locale variant is // instantly stale after the bump. Stale transients expire naturally // on their existing TTL and are garbage-collected by WordPress. - $version = (int) get_option('opentrust_cache_version', 1); - update_option('opentrust_cache_version', $version + 1, false); + $version = (int) get_option('ettic_otc_cache_version', 1); + update_option('ettic_otc_cache_version', $version + 1, false); } diff --git a/includes/data/certification-catalog.php b/includes/data/certification-catalog.php index 031eb3d..56c16a4 100644 --- a/includes/data/certification-catalog.php +++ b/includes/data/certification-catalog.php @@ -3,18 +3,18 @@ * Certification catalog. * * Curated list of common compliance frameworks, regulations, and - * certifications shown in the admin typeahead on the opentr_certification - * create screen. Each entry sets `_opentrust_cert_type` to either `certified` + * certifications shown in the admin typeahead on the eotc_certification + * create screen. Each entry sets `_ettic_otc_cert_type` to either `certified` * (third-party audited, has a certificate with dates and an issuing body) * or `compliant` (self-attested adherence to a standard or regulation). * - * Certified entries include `_opentrust_cert_issuing_body`. Compliant entries + * Certified entries include `_ettic_otc_cert_issuing_body`. Compliant entries * deliberately omit it because there is no auditor. * * Never auto-filled: issue date, expiry date, status, badge. Those are * user specific. * - * Extend without forking via the `opentrust_certification_catalog` filter. + * Extend without forking via the `ettic_otc_certification_catalog` filter. */ declare(strict_types=1); @@ -29,9 +29,9 @@ 'name' => 'SOC 2 Type I', 'aliases' => [ 'soc2 type 1', 'soc 2 type 1', 'soc2 type i' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'Point in time audit of the design of controls against the AICPA Trust Services Criteria (Security, Availability, Processing Integrity, Confidentiality, Privacy).', - '_opentrust_cert_issuing_body' => 'AICPA', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'Point in time audit of the design of controls against the AICPA Trust Services Criteria (Security, Availability, Processing Integrity, Confidentiality, Privacy).', + '_ettic_otc_cert_issuing_body' => 'AICPA', ], 'fields_review' => [], ], @@ -40,9 +40,9 @@ 'name' => 'SOC 2 Type II', 'aliases' => [ 'soc2 type 2', 'soc 2 type 2', 'soc2', 'soc 2' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'Audit of the design and operating effectiveness of controls over a period (typically 6 to 12 months) against the AICPA Trust Services Criteria.', - '_opentrust_cert_issuing_body' => 'AICPA', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'Audit of the design and operating effectiveness of controls over a period (typically 6 to 12 months) against the AICPA Trust Services Criteria.', + '_ettic_otc_cert_issuing_body' => 'AICPA', ], 'fields_review' => [], ], @@ -51,9 +51,9 @@ 'name' => 'SOC 1 Type II', 'aliases' => [ 'soc1 type 2', 'soc 1', 'ssae 18' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'Audit of controls relevant to a service organization\'s impact on user entities\' internal control over financial reporting, conducted under SSAE 18.', - '_opentrust_cert_issuing_body' => 'AICPA', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'Audit of controls relevant to a service organization\'s impact on user entities\' internal control over financial reporting, conducted under SSAE 18.', + '_ettic_otc_cert_issuing_body' => 'AICPA', ], 'fields_review' => [], ], @@ -62,9 +62,9 @@ 'name' => 'ISO/IEC 27001', 'aliases' => [ 'iso 27001', 'iso27001', 'isms' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'International standard for establishing, implementing, and maintaining an Information Security Management System (ISMS).', - '_opentrust_cert_issuing_body' => 'ISO/IEC accredited certification body', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'International standard for establishing, implementing, and maintaining an Information Security Management System (ISMS).', + '_ettic_otc_cert_issuing_body' => 'ISO/IEC accredited certification body', ], 'fields_review' => [], ], @@ -73,9 +73,9 @@ 'name' => 'ISO/IEC 27017', 'aliases' => [ 'iso 27017', 'iso27017' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'Code of practice providing additional information security controls for cloud service providers and cloud customers, extending ISO/IEC 27002.', - '_opentrust_cert_issuing_body' => 'ISO/IEC accredited certification body', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'Code of practice providing additional information security controls for cloud service providers and cloud customers, extending ISO/IEC 27002.', + '_ettic_otc_cert_issuing_body' => 'ISO/IEC accredited certification body', ], 'fields_review' => [], ], @@ -84,9 +84,9 @@ 'name' => 'ISO/IEC 27018', 'aliases' => [ 'iso 27018', 'iso27018' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'Code of practice for the protection of personally identifiable information (PII) in public clouds acting as PII processors.', - '_opentrust_cert_issuing_body' => 'ISO/IEC accredited certification body', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'Code of practice for the protection of personally identifiable information (PII) in public clouds acting as PII processors.', + '_ettic_otc_cert_issuing_body' => 'ISO/IEC accredited certification body', ], 'fields_review' => [], ], @@ -95,9 +95,9 @@ 'name' => 'ISO/IEC 27701', 'aliases' => [ 'iso 27701', 'iso27701', 'pims' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'Extension to ISO/IEC 27001 specifying requirements for a Privacy Information Management System (PIMS) covering PII controllers and processors.', - '_opentrust_cert_issuing_body' => 'ISO/IEC accredited certification body', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'Extension to ISO/IEC 27001 specifying requirements for a Privacy Information Management System (PIMS) covering PII controllers and processors.', + '_ettic_otc_cert_issuing_body' => 'ISO/IEC accredited certification body', ], 'fields_review' => [], ], @@ -106,9 +106,9 @@ 'name' => 'ISO 9001', 'aliases' => [ 'iso9001', 'quality management' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'International standard for Quality Management Systems (QMS), covering processes for consistent product and service delivery and continual improvement.', - '_opentrust_cert_issuing_body' => 'ISO accredited certification body', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'International standard for Quality Management Systems (QMS), covering processes for consistent product and service delivery and continual improvement.', + '_ettic_otc_cert_issuing_body' => 'ISO accredited certification body', ], 'fields_review' => [], ], @@ -117,8 +117,8 @@ 'name' => 'HIPAA', 'aliases' => [ 'hipaa', 'health insurance portability', 'phi' ], 'fields' => [ - '_opentrust_cert_type' => 'compliant', - '_opentrust_cert_description' => 'US federal law governing the protection and confidential handling of individually identifiable health information (PHI) by covered entities and business associates.', + '_ettic_otc_cert_type' => 'compliant', + '_ettic_otc_cert_description' => 'US federal law governing the protection and confidential handling of individually identifiable health information (PHI) by covered entities and business associates.', ], 'fields_review' => [], ], @@ -127,9 +127,9 @@ 'name' => 'PCI DSS', 'aliases' => [ 'pci', 'pci-dss', 'payment card industry' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'Payment Card Industry Data Security Standard defining technical and operational requirements for organizations that store, process, or transmit cardholder data.', - '_opentrust_cert_issuing_body' => 'PCI Security Standards Council', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'Payment Card Industry Data Security Standard defining technical and operational requirements for organizations that store, process, or transmit cardholder data.', + '_ettic_otc_cert_issuing_body' => 'PCI Security Standards Council', ], 'fields_review' => [], ], @@ -138,8 +138,8 @@ 'name' => 'GDPR', 'aliases' => [ 'gdpr', 'general data protection regulation', 'eu gdpr' ], 'fields' => [ - '_opentrust_cert_type' => 'compliant', - '_opentrust_cert_description' => 'European Union regulation governing the processing of personal data of individuals in the EU and EEA, including data subject rights and cross-border transfers.', + '_ettic_otc_cert_type' => 'compliant', + '_ettic_otc_cert_description' => 'European Union regulation governing the processing of personal data of individuals in the EU and EEA, including data subject rights and cross-border transfers.', ], 'fields_review' => [], ], @@ -148,8 +148,8 @@ 'name' => 'NIS2', 'aliases' => [ 'nis2', 'nis 2', 'network and information security directive', 'eu nis2' ], 'fields' => [ - '_opentrust_cert_type' => 'compliant', - '_opentrust_cert_description' => 'European Union directive on measures for a high common level of cybersecurity across the Union, setting risk management, incident reporting, and supply chain security requirements for essential and important entities.', + '_ettic_otc_cert_type' => 'compliant', + '_ettic_otc_cert_description' => 'European Union directive on measures for a high common level of cybersecurity across the Union, setting risk management, incident reporting, and supply chain security requirements for essential and important entities.', ], 'fields_review' => [], ], @@ -158,8 +158,8 @@ 'name' => 'CCPA', 'aliases' => [ 'ccpa', 'cpra', 'california consumer privacy act' ], 'fields' => [ - '_opentrust_cert_type' => 'compliant', - '_opentrust_cert_description' => 'California state law granting consumers rights over personal information collected by businesses, as amended by the California Privacy Rights Act (CPRA).', + '_ettic_otc_cert_type' => 'compliant', + '_ettic_otc_cert_description' => 'California state law granting consumers rights over personal information collected by businesses, as amended by the California Privacy Rights Act (CPRA).', ], 'fields_review' => [], ], @@ -168,9 +168,9 @@ 'name' => 'HITRUST CSF', 'aliases' => [ 'hitrust', 'hitrust csf', 'csf' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'Certifiable framework that harmonizes requirements from HIPAA, ISO, NIST, PCI, and other standards into a single set of controls for managing information risk.', - '_opentrust_cert_issuing_body' => 'HITRUST Alliance', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'Certifiable framework that harmonizes requirements from HIPAA, ISO, NIST, PCI, and other standards into a single set of controls for managing information risk.', + '_ettic_otc_cert_issuing_body' => 'HITRUST Alliance', ], 'fields_review' => [], ], @@ -179,9 +179,9 @@ 'name' => 'Cyber Essentials', 'aliases' => [ 'ce', 'uk cyber essentials' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'UK government-backed scheme covering five technical controls (firewalls, secure configuration, access control, malware protection, patch management), verified by self-assessment.', - '_opentrust_cert_issuing_body' => 'IASME (on behalf of UK NCSC)', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'UK government-backed scheme covering five technical controls (firewalls, secure configuration, access control, malware protection, patch management), verified by self-assessment.', + '_ettic_otc_cert_issuing_body' => 'IASME (on behalf of UK NCSC)', ], 'fields_review' => [], ], @@ -190,9 +190,9 @@ 'name' => 'Cyber Essentials Plus', 'aliases' => [ 'ce+', 'ce plus', 'cyber essentials +' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'Higher assurance tier of Cyber Essentials, adding hands-on technical verification and vulnerability testing of the same five control areas by an accredited assessor.', - '_opentrust_cert_issuing_body' => 'IASME (on behalf of UK NCSC)', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'Higher assurance tier of Cyber Essentials, adding hands-on technical verification and vulnerability testing of the same five control areas by an accredited assessor.', + '_ettic_otc_cert_issuing_body' => 'IASME (on behalf of UK NCSC)', ], 'fields_review' => [], ], @@ -201,9 +201,9 @@ 'name' => 'FedRAMP', 'aliases' => [ 'fedramp', 'federal risk and authorization management program' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'US government program that standardizes security assessment, authorization, and continuous monitoring for cloud products and services used by federal agencies.', - '_opentrust_cert_issuing_body' => 'US General Services Administration (GSA)', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'US government program that standardizes security assessment, authorization, and continuous monitoring for cloud products and services used by federal agencies.', + '_ettic_otc_cert_issuing_body' => 'US General Services Administration (GSA)', ], 'fields_review' => [], ], @@ -212,9 +212,9 @@ 'name' => 'CMMC', 'aliases' => [ 'cmmc', 'cybersecurity maturity model certification' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'US Department of Defense framework certifying contractor cybersecurity practices for the protection of Federal Contract Information (FCI) and Controlled Unclassified Information (CUI).', - '_opentrust_cert_issuing_body' => 'Cyber AB (on behalf of US DoD)', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'US Department of Defense framework certifying contractor cybersecurity practices for the protection of Federal Contract Information (FCI) and Controlled Unclassified Information (CUI).', + '_ettic_otc_cert_issuing_body' => 'Cyber AB (on behalf of US DoD)', ], 'fields_review' => [], ], @@ -223,9 +223,9 @@ 'name' => 'TISAX', 'aliases' => [ 'tisax', 'trusted information security assessment exchange' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'Information security assessment and exchange mechanism developed for the automotive industry, based on the VDA ISA catalog.', - '_opentrust_cert_issuing_body' => 'ENX Association', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'Information security assessment and exchange mechanism developed for the automotive industry, based on the VDA ISA catalog.', + '_ettic_otc_cert_issuing_body' => 'ENX Association', ], 'fields_review' => [], ], @@ -234,9 +234,9 @@ 'name' => 'BSI C5', 'aliases' => [ 'c5', 'cloud computing compliance criteria catalogue' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'German government catalog of minimum baseline security requirements for cloud service providers, assessed through an independent audit report.', - '_opentrust_cert_issuing_body' => 'Germany Federal Office for Information Security (BSI)', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'German government catalog of minimum baseline security requirements for cloud service providers, assessed through an independent audit report.', + '_ettic_otc_cert_issuing_body' => 'Germany Federal Office for Information Security (BSI)', ], 'fields_review' => [], ], @@ -245,9 +245,9 @@ 'name' => 'IRAP', 'aliases' => [ 'irap', 'information security registered assessors program' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'Australian government assessment of an ICT system against the Information Security Manual (ISM), performed by endorsed assessors for use by Australian government entities.', - '_opentrust_cert_issuing_body' => 'Australian Signals Directorate (ASD)', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'Australian government assessment of an ICT system against the Information Security Manual (ISM), performed by endorsed assessors for use by Australian government entities.', + '_ettic_otc_cert_issuing_body' => 'Australian Signals Directorate (ASD)', ], 'fields_review' => [], ], @@ -256,9 +256,9 @@ 'name' => 'HDS', 'aliases' => [ 'hds', 'hebergeur de donnees de sante', 'health data hosting' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'French certification required for hosting personal health data, covering infrastructure and application hosting activities under the French Public Health Code.', - '_opentrust_cert_issuing_body' => 'French Agence du Numerique en Sante (ANS)', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'French certification required for hosting personal health data, covering infrastructure and application hosting activities under the French Public Health Code.', + '_ettic_otc_cert_issuing_body' => 'French Agence du Numerique en Sante (ANS)', ], 'fields_review' => [], ], @@ -267,8 +267,8 @@ 'name' => 'CSA STAR Level 1', 'aliases' => [ 'star level 1', 'csa star 1', 'caiq' ], 'fields' => [ - '_opentrust_cert_type' => 'compliant', - '_opentrust_cert_description' => 'Self-assessment published to the Cloud Security Alliance STAR registry, documenting cloud security controls against the Cloud Controls Matrix (CCM) and CAIQ.', + '_ettic_otc_cert_type' => 'compliant', + '_ettic_otc_cert_description' => 'Self-assessment published to the Cloud Security Alliance STAR registry, documenting cloud security controls against the Cloud Controls Matrix (CCM) and CAIQ.', ], 'fields_review' => [], ], @@ -277,9 +277,9 @@ 'name' => 'CSA STAR Level 2', 'aliases' => [ 'star level 2', 'csa star 2', 'star certification' ], 'fields' => [ - '_opentrust_cert_type' => 'certified', - '_opentrust_cert_description' => 'Third-party audit of cloud security controls against the Cloud Controls Matrix, performed alongside an ISO/IEC 27001 certification or a SOC 2 attestation.', - '_opentrust_cert_issuing_body' => 'Cloud Security Alliance (via accredited auditor)', + '_ettic_otc_cert_type' => 'certified', + '_ettic_otc_cert_description' => 'Third-party audit of cloud security controls against the Cloud Controls Matrix, performed alongside an ISO/IEC 27001 certification or a SOC 2 attestation.', + '_ettic_otc_cert_issuing_body' => 'Cloud Security Alliance (via accredited auditor)', ], 'fields_review' => [], ], diff --git a/includes/data/data-practice-catalog.php b/includes/data/data-practice-catalog.php index 01b2d7d..a01636f 100644 --- a/includes/data/data-practice-catalog.php +++ b/includes/data/data-practice-catalog.php @@ -3,12 +3,12 @@ * Data-practice catalog. * * Templates for common data-practice categories. Used by the admin typeahead - * on the opentr_data_practice create screen. Every entry is a starting point — + * on the eotc_data_practice create screen. Every entry is a starting point — * users must review legal basis, retention, and shared-with lists before * publishing. All template fields live under `fields_review` so the UI marks * them as "verify before publishing". * - * Extend without forking via the `opentrust_data_practice_catalog` filter. + * Extend without forking via the `ettic_otc_data_practice_catalog` filter. * * Legal basis values must match keys in Ettic_OTC_Render::legal_basis_labels(). */ @@ -26,11 +26,11 @@ 'aliases' => [ 'analytics', 'web analytics', 'site analytics', 'ga', 'google analytics' ], 'fields' => [], 'fields_review' => [ - '_opentrust_dp_purpose' => 'Measure website traffic, understand visitor behavior, and improve content and navigation.', - '_opentrust_dp_legal_basis' => 'legitimate_interest', - '_opentrust_dp_retention_period' => '14 months', - '_opentrust_dp_data_items' => [ 'IP address', 'Browser and device', 'Page views', 'Referrer', 'Session duration' ], - '_opentrust_dp_shared_with' => [ 'Analytics provider' ], + '_ettic_otc_dp_purpose' => 'Measure website traffic, understand visitor behavior, and improve content and navigation.', + '_ettic_otc_dp_legal_basis' => 'legitimate_interest', + '_ettic_otc_dp_retention_period' => '14 months', + '_ettic_otc_dp_data_items' => [ 'IP address', 'Browser and device', 'Page views', 'Referrer', 'Session duration' ], + '_ettic_otc_dp_shared_with' => [ 'Analytics provider' ], ], ], @@ -39,11 +39,11 @@ 'aliases' => [ 'telemetry', 'product analytics', 'usage analytics', 'events' ], 'fields' => [], 'fields_review' => [ - '_opentrust_dp_purpose' => 'Track in-product feature usage to prioritize improvements and diagnose problems.', - '_opentrust_dp_legal_basis' => 'legitimate_interest', - '_opentrust_dp_retention_period' => '24 months', - '_opentrust_dp_data_items' => [ 'User ID', 'Feature events', 'Session metadata', 'Device and OS' ], - '_opentrust_dp_shared_with' => [ 'Product analytics provider' ], + '_ettic_otc_dp_purpose' => 'Track in-product feature usage to prioritize improvements and diagnose problems.', + '_ettic_otc_dp_legal_basis' => 'legitimate_interest', + '_ettic_otc_dp_retention_period' => '24 months', + '_ettic_otc_dp_data_items' => [ 'User ID', 'Feature events', 'Session metadata', 'Device and OS' ], + '_ettic_otc_dp_shared_with' => [ 'Product analytics provider' ], ], ], @@ -52,11 +52,11 @@ 'aliases' => [ 'error tracking', 'crash reporting', 'sentry', 'bug tracking', 'exceptions' ], 'fields' => [], 'fields_review' => [ - '_opentrust_dp_purpose' => 'Detect and diagnose application errors to maintain service reliability and security.', - '_opentrust_dp_legal_basis' => 'legitimate_interest', - '_opentrust_dp_retention_period' => '90 days', - '_opentrust_dp_data_items' => [ 'Stack trace', 'User ID', 'Request URL', 'Browser and device' ], - '_opentrust_dp_shared_with' => [ 'Error monitoring provider' ], + '_ettic_otc_dp_purpose' => 'Detect and diagnose application errors to maintain service reliability and security.', + '_ettic_otc_dp_legal_basis' => 'legitimate_interest', + '_ettic_otc_dp_retention_period' => '90 days', + '_ettic_otc_dp_data_items' => [ 'Stack trace', 'User ID', 'Request URL', 'Browser and device' ], + '_ettic_otc_dp_shared_with' => [ 'Error monitoring provider' ], ], ], @@ -65,11 +65,11 @@ 'aliases' => [ 'email', 'service email', 'notifications', 'receipts', 'password reset' ], 'fields' => [], 'fields_review' => [ - '_opentrust_dp_purpose' => 'Send account-related and service-related emails such as receipts, password resets, and notifications.', - '_opentrust_dp_legal_basis' => 'contract', - '_opentrust_dp_retention_period' => 'Duration of account', - '_opentrust_dp_data_items' => [ 'Email address', 'Name', 'Email content' ], - '_opentrust_dp_shared_with' => [ 'Email delivery provider' ], + '_ettic_otc_dp_purpose' => 'Send account-related and service-related emails such as receipts, password resets, and notifications.', + '_ettic_otc_dp_legal_basis' => 'contract', + '_ettic_otc_dp_retention_period' => 'Duration of account', + '_ettic_otc_dp_data_items' => [ 'Email address', 'Name', 'Email content' ], + '_ettic_otc_dp_shared_with' => [ 'Email delivery provider' ], ], ], @@ -78,11 +78,11 @@ 'aliases' => [ 'newsletter', 'marketing', 'promotional email', 'email marketing' ], 'fields' => [], 'fields_review' => [ - '_opentrust_dp_purpose' => 'Send product updates, newsletters, and promotional messages to users who have opted in.', - '_opentrust_dp_legal_basis' => 'consent', - '_opentrust_dp_retention_period' => 'Until unsubscribe', - '_opentrust_dp_data_items' => [ 'Email address', 'Name', 'Subscription preferences' ], - '_opentrust_dp_shared_with' => [ 'Email marketing provider' ], + '_ettic_otc_dp_purpose' => 'Send product updates, newsletters, and promotional messages to users who have opted in.', + '_ettic_otc_dp_legal_basis' => 'consent', + '_ettic_otc_dp_retention_period' => 'Until unsubscribe', + '_ettic_otc_dp_data_items' => [ 'Email address', 'Name', 'Subscription preferences' ], + '_ettic_otc_dp_shared_with' => [ 'Email marketing provider' ], ], ], @@ -91,11 +91,11 @@ 'aliases' => [ 'support', 'helpdesk', 'help desk', 'tickets', 'customer service' ], 'fields' => [], 'fields_review' => [ - '_opentrust_dp_purpose' => 'Respond to customer inquiries and maintain a record of support interactions.', - '_opentrust_dp_legal_basis' => 'contract', - '_opentrust_dp_retention_period' => '3 years after case closure', - '_opentrust_dp_data_items' => [ 'Name', 'Email address', 'Message contents', 'Account ID' ], - '_opentrust_dp_shared_with' => [ 'Support platform provider' ], + '_ettic_otc_dp_purpose' => 'Respond to customer inquiries and maintain a record of support interactions.', + '_ettic_otc_dp_legal_basis' => 'contract', + '_ettic_otc_dp_retention_period' => '3 years after case closure', + '_ettic_otc_dp_data_items' => [ 'Name', 'Email address', 'Message contents', 'Account ID' ], + '_ettic_otc_dp_shared_with' => [ 'Support platform provider' ], ], ], @@ -104,11 +104,11 @@ 'aliases' => [ 'payments', 'billing', 'stripe', 'subscriptions', 'checkout' ], 'fields' => [], 'fields_review' => [ - '_opentrust_dp_purpose' => 'Process payments for subscriptions or one-time purchases and manage billing records.', - '_opentrust_dp_legal_basis' => 'contract', - '_opentrust_dp_retention_period' => '7 years (tax and accounting obligation)', - '_opentrust_dp_data_items' => [ 'Name', 'Billing address', 'Email address', 'Payment method (tokenized)', 'Transaction history' ], - '_opentrust_dp_shared_with' => [ 'Payment processor' ], + '_ettic_otc_dp_purpose' => 'Process payments for subscriptions or one-time purchases and manage billing records.', + '_ettic_otc_dp_legal_basis' => 'contract', + '_ettic_otc_dp_retention_period' => '7 years (tax and accounting obligation)', + '_ettic_otc_dp_data_items' => [ 'Name', 'Billing address', 'Email address', 'Payment method (tokenized)', 'Transaction history' ], + '_ettic_otc_dp_shared_with' => [ 'Payment processor' ], ], ], @@ -117,11 +117,11 @@ 'aliases' => [ 'auth', 'login', 'sign in', 'signup', 'account', 'session' ], 'fields' => [], 'fields_review' => [ - '_opentrust_dp_purpose' => 'Create and maintain user accounts, authenticate sign-in attempts, and secure sessions.', - '_opentrust_dp_legal_basis' => 'contract', - '_opentrust_dp_retention_period' => 'Duration of account + 30 days', - '_opentrust_dp_data_items' => [ 'Email address', 'Password (hashed)', 'Session tokens', 'Last sign-in IP' ], - '_opentrust_dp_shared_with' => [ 'Authentication provider' ], + '_ettic_otc_dp_purpose' => 'Create and maintain user accounts, authenticate sign-in attempts, and secure sessions.', + '_ettic_otc_dp_legal_basis' => 'contract', + '_ettic_otc_dp_retention_period' => 'Duration of account + 30 days', + '_ettic_otc_dp_data_items' => [ 'Email address', 'Password (hashed)', 'Session tokens', 'Last sign-in IP' ], + '_ettic_otc_dp_shared_with' => [ 'Authentication provider' ], ], ], @@ -130,11 +130,11 @@ 'aliases' => [ 'session recording', 'replay', 'fullstory', 'logrocket', 'heatmaps' ], 'fields' => [], 'fields_review' => [ - '_opentrust_dp_purpose' => 'Record anonymized user sessions to diagnose usability issues and improve the product.', - '_opentrust_dp_legal_basis' => 'legitimate_interest', - '_opentrust_dp_retention_period' => '30 days', - '_opentrust_dp_data_items' => [ 'Mouse movements', 'Click events', 'Page navigation', 'Screen size' ], - '_opentrust_dp_shared_with' => [ 'Session replay provider' ], + '_ettic_otc_dp_purpose' => 'Record anonymized user sessions to diagnose usability issues and improve the product.', + '_ettic_otc_dp_legal_basis' => 'legitimate_interest', + '_ettic_otc_dp_retention_period' => '30 days', + '_ettic_otc_dp_data_items' => [ 'Mouse movements', 'Click events', 'Page navigation', 'Screen size' ], + '_ettic_otc_dp_shared_with' => [ 'Session replay provider' ], ], ], @@ -143,11 +143,11 @@ 'aliases' => [ 'crm', 'contacts', 'hubspot', 'salesforce', 'pipedrive' ], 'fields' => [], 'fields_review' => [ - '_opentrust_dp_purpose' => 'Manage customer relationships and track sales and account interactions.', - '_opentrust_dp_legal_basis' => 'legitimate_interest', - '_opentrust_dp_retention_period' => 'Duration of relationship + 3 years', - '_opentrust_dp_data_items' => [ 'Name', 'Email address', 'Company', 'Job title', 'Interaction history' ], - '_opentrust_dp_shared_with' => [ 'CRM provider' ], + '_ettic_otc_dp_purpose' => 'Manage customer relationships and track sales and account interactions.', + '_ettic_otc_dp_legal_basis' => 'legitimate_interest', + '_ettic_otc_dp_retention_period' => 'Duration of relationship + 3 years', + '_ettic_otc_dp_data_items' => [ 'Name', 'Email address', 'Company', 'Job title', 'Interaction history' ], + '_ettic_otc_dp_shared_with' => [ 'CRM provider' ], ], ], @@ -156,11 +156,11 @@ 'aliases' => [ 'audit log', 'security log', 'access log', 'siem' ], 'fields' => [], 'fields_review' => [ - '_opentrust_dp_purpose' => 'Detect and investigate security events, prevent abuse, and meet compliance obligations.', - '_opentrust_dp_legal_basis' => 'legitimate_interest', - '_opentrust_dp_retention_period' => '12 months', - '_opentrust_dp_data_items' => [ 'User ID', 'IP address', 'Action performed', 'Timestamp', 'User agent' ], - '_opentrust_dp_shared_with' => [ 'Logging and SIEM providers' ], + '_ettic_otc_dp_purpose' => 'Detect and investigate security events, prevent abuse, and meet compliance obligations.', + '_ettic_otc_dp_legal_basis' => 'legitimate_interest', + '_ettic_otc_dp_retention_period' => '12 months', + '_ettic_otc_dp_data_items' => [ 'User ID', 'IP address', 'Action performed', 'Timestamp', 'User agent' ], + '_ettic_otc_dp_shared_with' => [ 'Logging and SIEM providers' ], ], ], @@ -169,11 +169,11 @@ 'aliases' => [ 'hosting', 'cloud', 'aws', 'gcp', 'server' ], 'fields' => [], 'fields_review' => [ - '_opentrust_dp_purpose' => 'Store and serve application data, run backend services, and deliver the product to users.', - '_opentrust_dp_legal_basis' => 'contract', - '_opentrust_dp_retention_period' => 'Duration of account', - '_opentrust_dp_data_items' => [ 'All user-submitted data', 'Account information', 'Application state' ], - '_opentrust_dp_shared_with' => [ 'Cloud infrastructure provider' ], + '_ettic_otc_dp_purpose' => 'Store and serve application data, run backend services, and deliver the product to users.', + '_ettic_otc_dp_legal_basis' => 'contract', + '_ettic_otc_dp_retention_period' => 'Duration of account', + '_ettic_otc_dp_data_items' => [ 'All user-submitted data', 'Account information', 'Application state' ], + '_ettic_otc_dp_shared_with' => [ 'Cloud infrastructure provider' ], ], ], diff --git a/includes/data/faq-catalog.php b/includes/data/faq-catalog.php index 216d747..2240146 100644 --- a/includes/data/faq-catalog.php +++ b/includes/data/faq-catalog.php @@ -2,7 +2,7 @@ /** * Default FAQ catalog. * - * Generic, content-agnostic glossary entries seeded into the opentr_faq CPT on + * Generic, content-agnostic glossary entries seeded into the eotc_faq CPT on * first plugin activation. These explain universal trust-center concepts and * make no claims about the specific company running the plugin. * @@ -13,8 +13,8 @@ * block at seed time and stored as post_content).', * ] * - * Filterable via the `opentrust_faq_catalog` filter. Because seeding is gated - * by the `opentrust_faqs_seeded` option, editing this file after first + * Filterable via the `ettic_otc_faq_catalog` filter. Because seeding is gated + * by the `ettic_otc_faqs_seeded` option, editing this file after first * activation has no effect on existing installs. */ diff --git a/includes/data/subprocessor-catalog.php b/includes/data/subprocessor-catalog.php index f18c888..0502a5c 100644 --- a/includes/data/subprocessor-catalog.php +++ b/includes/data/subprocessor-catalog.php @@ -3,26 +3,26 @@ * Subprocessor catalog. * * Curated list of common SaaS vendors with factual information that can be - * auto-filled into the opentr_subprocessor meta box from the admin typeahead. + * auto-filled into the eotc_subprocessor meta box from the admin typeahead. * * Schema per entry: * 'slug' => [ * 'name' => 'Canonical Name', * 'aliases' => ['alt', 'nickname'], - * 'fields' => [ '_opentrust_sub_*' => string ], // verified facts - * 'fields_review' => [ '_opentrust_sub_*' => string ], // templates to verify + * 'fields' => [ '_ettic_otc_sub_*' => string ], // verified facts + * 'fields_review' => [ '_ettic_otc_sub_*' => string ], // templates to verify * ] * * Rules followed by this catalog: - * 1. `_opentrust_sub_country` is included only when the HQ / processing region is + * 1. `_ettic_otc_sub_country` is included only when the HQ / processing region is * unambiguous. Multi-region cloud infra (AWS, GCP, Azure, Cloudflare, * Fastly, Vercel, etc.) deliberately omits the key so the customer picks. - * 2. `_opentrust_sub_data_processed` is always a template in `fields_review` so + * 2. `_ettic_otc_sub_data_processed` is always a template in `fields_review` so * the UI marks it for user verification before publishing. The text is * a reasonable starting point only. - * 3. `_opentrust_sub_dpa_signed` is never touched because that is contract state. + * 3. `_ettic_otc_sub_dpa_signed` is never touched because that is contract state. * - * Extend without forking via the `opentrust_subprocessor_catalog` filter. + * Extend without forking via the `ettic_otc_subprocessor_catalog` filter. */ declare(strict_types=1); @@ -37,11 +37,11 @@ 'name' => 'Amazon Web Services', 'aliases' => [ 'aws', 'amazon web services', 'amazon aws' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Cloud infrastructure, compute, storage, and managed services.', - '_opentrust_sub_website' => 'https://aws.amazon.com', + '_ettic_otc_sub_purpose' => 'Cloud infrastructure, compute, storage, and managed services.', + '_ettic_otc_sub_website' => 'https://aws.amazon.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application data, user-generated content, system logs, and backups stored across compute, storage, and database services.', + '_ettic_otc_sub_data_processed' => 'Application data, user-generated content, system logs, and backups stored across compute, storage, and database services.', ], ], @@ -49,11 +49,11 @@ 'name' => 'Google Cloud Platform', 'aliases' => [ 'gcp', 'google cloud', 'google cloud platform' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Cloud infrastructure, compute, storage, and managed services.', - '_opentrust_sub_website' => 'https://cloud.google.com', + '_ettic_otc_sub_purpose' => 'Cloud infrastructure, compute, storage, and managed services.', + '_ettic_otc_sub_website' => 'https://cloud.google.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application data, user-generated content, system logs, and backups stored across compute, storage, and database services.', + '_ettic_otc_sub_data_processed' => 'Application data, user-generated content, system logs, and backups stored across compute, storage, and database services.', ], ], @@ -61,11 +61,11 @@ 'name' => 'Microsoft Azure', 'aliases' => [ 'azure', 'microsoft azure', 'ms azure' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Cloud infrastructure, compute, storage, and managed services.', - '_opentrust_sub_website' => 'https://azure.microsoft.com', + '_ettic_otc_sub_purpose' => 'Cloud infrastructure, compute, storage, and managed services.', + '_ettic_otc_sub_website' => 'https://azure.microsoft.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application data, user-generated content, system logs, and backups stored across compute, storage, and database services.', + '_ettic_otc_sub_data_processed' => 'Application data, user-generated content, system logs, and backups stored across compute, storage, and database services.', ], ], @@ -73,11 +73,11 @@ 'name' => 'Cloudflare', 'aliases' => [ 'cloudflare', 'cf' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Content delivery network, DDoS protection, DNS, and edge compute.', - '_opentrust_sub_website' => 'https://cloudflare.com', + '_ettic_otc_sub_purpose' => 'Content delivery network, DDoS protection, DNS, and edge compute.', + '_ettic_otc_sub_website' => 'https://cloudflare.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'HTTP request metadata, IP addresses, request headers, and cached content served to end users.', + '_ettic_otc_sub_data_processed' => 'HTTP request metadata, IP addresses, request headers, and cached content served to end users.', ], ], @@ -85,11 +85,11 @@ 'name' => 'Vercel', 'aliases' => [ 'vercel', 'zeit', 'zeit now' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Frontend hosting, serverless functions, and edge deployment platform.', - '_opentrust_sub_website' => 'https://vercel.com', + '_ettic_otc_sub_purpose' => 'Frontend hosting, serverless functions, and edge deployment platform.', + '_ettic_otc_sub_website' => 'https://vercel.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application source code, build artifacts, request logs, and runtime data for deployed sites and functions.', + '_ettic_otc_sub_data_processed' => 'Application source code, build artifacts, request logs, and runtime data for deployed sites and functions.', ], ], @@ -97,11 +97,11 @@ 'name' => 'Netlify', 'aliases' => [ 'netlify' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Frontend hosting, serverless functions, and continuous deployment platform.', - '_opentrust_sub_website' => 'https://netlify.com', + '_ettic_otc_sub_purpose' => 'Frontend hosting, serverless functions, and continuous deployment platform.', + '_ettic_otc_sub_website' => 'https://netlify.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application source code, build artifacts, request logs, and runtime data for deployed sites and functions.', + '_ettic_otc_sub_data_processed' => 'Application source code, build artifacts, request logs, and runtime data for deployed sites and functions.', ], ], @@ -109,11 +109,11 @@ 'name' => 'Fly.io', 'aliases' => [ 'fly', 'fly.io', 'flyio' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Application hosting platform running containers on a global edge network.', - '_opentrust_sub_website' => 'https://fly.io', + '_ettic_otc_sub_purpose' => 'Application hosting platform running containers on a global edge network.', + '_ettic_otc_sub_website' => 'https://fly.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application containers, runtime data, logs, and persistent volumes for deployed services.', + '_ettic_otc_sub_data_processed' => 'Application containers, runtime data, logs, and persistent volumes for deployed services.', ], ], @@ -121,11 +121,11 @@ 'name' => 'Railway', 'aliases' => [ 'railway', 'railway.app' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Application hosting and deployment platform for containers and databases.', - '_opentrust_sub_website' => 'https://railway.app', + '_ettic_otc_sub_purpose' => 'Application hosting and deployment platform for containers and databases.', + '_ettic_otc_sub_website' => 'https://railway.app', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application source, runtime data, environment variables, and database contents for deployed services.', + '_ettic_otc_sub_data_processed' => 'Application source, runtime data, environment variables, and database contents for deployed services.', ], ], @@ -133,11 +133,11 @@ 'name' => 'Render', 'aliases' => [ 'render', 'render.com' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Application hosting platform for web services, databases, and background workers.', - '_opentrust_sub_website' => 'https://render.com', + '_ettic_otc_sub_purpose' => 'Application hosting platform for web services, databases, and background workers.', + '_ettic_otc_sub_website' => 'https://render.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application source, runtime data, logs, and database contents for deployed services.', + '_ettic_otc_sub_data_processed' => 'Application source, runtime data, logs, and database contents for deployed services.', ], ], @@ -145,11 +145,11 @@ 'name' => 'DigitalOcean', 'aliases' => [ 'digitalocean', 'digital ocean', 'do' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Cloud infrastructure provider offering virtual servers, managed databases, and object storage.', - '_opentrust_sub_website' => 'https://digitalocean.com', + '_ettic_otc_sub_purpose' => 'Cloud infrastructure provider offering virtual servers, managed databases, and object storage.', + '_ettic_otc_sub_website' => 'https://digitalocean.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application data, user-generated content, system logs, and backups stored on compute and storage services.', + '_ettic_otc_sub_data_processed' => 'Application data, user-generated content, system logs, and backups stored on compute and storage services.', ], ], @@ -157,11 +157,11 @@ 'name' => 'Linode', 'aliases' => [ 'linode', 'akamai linode' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Cloud infrastructure provider offering virtual servers and managed services.', - '_opentrust_sub_website' => 'https://linode.com', + '_ettic_otc_sub_purpose' => 'Cloud infrastructure provider offering virtual servers and managed services.', + '_ettic_otc_sub_website' => 'https://linode.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application data, user-generated content, system logs, and backups stored on compute and storage services.', + '_ettic_otc_sub_data_processed' => 'Application data, user-generated content, system logs, and backups stored on compute and storage services.', ], ], @@ -169,12 +169,12 @@ 'name' => 'Hetzner', 'aliases' => [ 'hetzner', 'hetzner online', 'hetzner cloud' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Cloud and dedicated server hosting provider.', - '_opentrust_sub_country' => 'DE', - '_opentrust_sub_website' => 'https://hetzner.com', + '_ettic_otc_sub_purpose' => 'Cloud and dedicated server hosting provider.', + '_ettic_otc_sub_country' => 'DE', + '_ettic_otc_sub_website' => 'https://hetzner.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application data, user-generated content, system logs, and backups stored on compute and storage services.', + '_ettic_otc_sub_data_processed' => 'Application data, user-generated content, system logs, and backups stored on compute and storage services.', ], ], @@ -182,11 +182,11 @@ 'name' => 'Fastly', 'aliases' => [ 'fastly' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Content delivery network and edge compute platform.', - '_opentrust_sub_website' => 'https://fastly.com', + '_ettic_otc_sub_purpose' => 'Content delivery network and edge compute platform.', + '_ettic_otc_sub_website' => 'https://fastly.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'HTTP request metadata, IP addresses, request headers, and cached content served to end users.', + '_ettic_otc_sub_data_processed' => 'HTTP request metadata, IP addresses, request headers, and cached content served to end users.', ], ], @@ -194,12 +194,12 @@ 'name' => 'Datadog', 'aliases' => [ 'datadog', 'data dog' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Infrastructure monitoring, application performance monitoring, and log management.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://datadoghq.com', + '_ettic_otc_sub_purpose' => 'Infrastructure monitoring, application performance monitoring, and log management.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://datadoghq.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'System metrics, application logs, traces, and error events including user identifiers contained in telemetry.', + '_ettic_otc_sub_data_processed' => 'System metrics, application logs, traces, and error events including user identifiers contained in telemetry.', ], ], @@ -207,12 +207,12 @@ 'name' => 'New Relic', 'aliases' => [ 'new relic', 'newrelic' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Application performance monitoring and observability platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://newrelic.com', + '_ettic_otc_sub_purpose' => 'Application performance monitoring and observability platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://newrelic.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'System metrics, application logs, traces, and error events including user identifiers contained in telemetry.', + '_ettic_otc_sub_data_processed' => 'System metrics, application logs, traces, and error events including user identifiers contained in telemetry.', ], ], @@ -220,12 +220,12 @@ 'name' => 'Sentry', 'aliases' => [ 'sentry', 'sentry.io', 'getsentry' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Error tracking and application performance monitoring.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://sentry.io', + '_ettic_otc_sub_purpose' => 'Error tracking and application performance monitoring.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://sentry.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Error stack traces, breadcrumbs, request context, user identifiers, and device metadata captured at error time.', + '_ettic_otc_sub_data_processed' => 'Error stack traces, breadcrumbs, request context, user identifiers, and device metadata captured at error time.', ], ], @@ -233,12 +233,12 @@ 'name' => 'LogRocket', 'aliases' => [ 'logrocket', 'log rocket' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Session replay and frontend monitoring for web applications.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://logrocket.com', + '_ettic_otc_sub_purpose' => 'Session replay and frontend monitoring for web applications.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://logrocket.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Recorded user sessions, DOM events, console logs, network requests, and user identifiers from end-user browsers.', + '_ettic_otc_sub_data_processed' => 'Recorded user sessions, DOM events, console logs, network requests, and user identifiers from end-user browsers.', ], ], @@ -246,12 +246,12 @@ 'name' => 'FullStory', 'aliases' => [ 'fullstory', 'full story' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Digital experience analytics and session replay for web and mobile.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://fullstory.com', + '_ettic_otc_sub_purpose' => 'Digital experience analytics and session replay for web and mobile.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://fullstory.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Recorded user sessions, click and scroll events, page content, and user identifiers from end-user devices.', + '_ettic_otc_sub_data_processed' => 'Recorded user sessions, click and scroll events, page content, and user identifiers from end-user devices.', ], ], @@ -259,12 +259,12 @@ 'name' => 'Honeycomb', 'aliases' => [ 'honeycomb', 'honeycomb.io' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Observability platform for distributed tracing and event-based debugging.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://honeycomb.io', + '_ettic_otc_sub_purpose' => 'Observability platform for distributed tracing and event-based debugging.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://honeycomb.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application traces, spans, events, and telemetry including user identifiers contained in instrumentation.', + '_ettic_otc_sub_data_processed' => 'Application traces, spans, events, and telemetry including user identifiers contained in instrumentation.', ], ], @@ -272,11 +272,11 @@ 'name' => 'Grafana Cloud', 'aliases' => [ 'grafana', 'grafana cloud', 'grafana labs' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Hosted observability platform for metrics, logs, traces, and dashboards.', - '_opentrust_sub_website' => 'https://grafana.com', + '_ettic_otc_sub_purpose' => 'Hosted observability platform for metrics, logs, traces, and dashboards.', + '_ettic_otc_sub_website' => 'https://grafana.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'System metrics, application logs, traces, and dashboard data including user identifiers contained in telemetry.', + '_ettic_otc_sub_data_processed' => 'System metrics, application logs, traces, and dashboard data including user identifiers contained in telemetry.', ], ], @@ -284,11 +284,11 @@ 'name' => 'Better Stack', 'aliases' => [ 'better stack', 'betterstack', 'better uptime', 'logtail' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Log management, uptime monitoring, and incident management platform.', - '_opentrust_sub_website' => 'https://betterstack.com', + '_ettic_otc_sub_purpose' => 'Log management, uptime monitoring, and incident management platform.', + '_ettic_otc_sub_website' => 'https://betterstack.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application logs, uptime check results, and incident metadata including user identifiers contained in log content.', + '_ettic_otc_sub_data_processed' => 'Application logs, uptime check results, and incident metadata including user identifiers contained in log content.', ], ], @@ -296,11 +296,11 @@ 'name' => 'Axiom', 'aliases' => [ 'axiom', 'axiom.co' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Cloud-native log management and event data platform.', - '_opentrust_sub_website' => 'https://axiom.co', + '_ettic_otc_sub_purpose' => 'Cloud-native log management and event data platform.', + '_ettic_otc_sub_website' => 'https://axiom.co', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application logs and event data including user identifiers contained in log content.', + '_ettic_otc_sub_data_processed' => 'Application logs and event data including user identifiers contained in log content.', ], ], @@ -308,11 +308,11 @@ 'name' => 'Baselime', 'aliases' => [ 'baselime' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Observability platform for serverless and cloud-native applications.', - '_opentrust_sub_website' => 'https://baselime.io', + '_ettic_otc_sub_purpose' => 'Observability platform for serverless and cloud-native applications.', + '_ettic_otc_sub_website' => 'https://baselime.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application logs, traces, and telemetry including user identifiers contained in instrumentation.', + '_ettic_otc_sub_data_processed' => 'Application logs, traces, and telemetry including user identifiers contained in instrumentation.', ], ], @@ -320,12 +320,12 @@ 'name' => 'Postmark', 'aliases' => [ 'postmark', 'postmarkapp' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Transactional email delivery service.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://postmarkapp.com', + '_ettic_otc_sub_purpose' => 'Transactional email delivery service.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://postmarkapp.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Recipient email addresses, message content, delivery metadata, and bounce or complaint events.', + '_ettic_otc_sub_data_processed' => 'Recipient email addresses, message content, delivery metadata, and bounce or complaint events.', ], ], @@ -333,12 +333,12 @@ 'name' => 'SendGrid', 'aliases' => [ 'sendgrid', 'twilio sendgrid' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Transactional and marketing email delivery service.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://sendgrid.com', + '_ettic_otc_sub_purpose' => 'Transactional and marketing email delivery service.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://sendgrid.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Recipient email addresses, message content, delivery metadata, and engagement events.', + '_ettic_otc_sub_data_processed' => 'Recipient email addresses, message content, delivery metadata, and engagement events.', ], ], @@ -346,12 +346,12 @@ 'name' => 'Resend', 'aliases' => [ 'resend', 'resend.com' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Transactional email delivery service for developers.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://resend.com', + '_ettic_otc_sub_purpose' => 'Transactional email delivery service for developers.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://resend.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Recipient email addresses, message content, delivery metadata, and bounce or complaint events.', + '_ettic_otc_sub_data_processed' => 'Recipient email addresses, message content, delivery metadata, and bounce or complaint events.', ], ], @@ -359,12 +359,12 @@ 'name' => 'Mailgun', 'aliases' => [ 'mailgun', 'sinch mailgun' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Transactional email delivery and validation service.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://mailgun.com', + '_ettic_otc_sub_purpose' => 'Transactional email delivery and validation service.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://mailgun.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Recipient email addresses, message content, delivery metadata, and engagement events.', + '_ettic_otc_sub_data_processed' => 'Recipient email addresses, message content, delivery metadata, and engagement events.', ], ], @@ -372,11 +372,11 @@ 'name' => 'Amazon SES', 'aliases' => [ 'ses', 'amazon ses', 'aws ses', 'simple email service' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Transactional email delivery service from Amazon Web Services.', - '_opentrust_sub_website' => 'https://aws.amazon.com/ses', + '_ettic_otc_sub_purpose' => 'Transactional email delivery service from Amazon Web Services.', + '_ettic_otc_sub_website' => 'https://aws.amazon.com/ses', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Recipient email addresses, message content, delivery metadata, and bounce or complaint events.', + '_ettic_otc_sub_data_processed' => 'Recipient email addresses, message content, delivery metadata, and bounce or complaint events.', ], ], @@ -384,12 +384,12 @@ 'name' => 'Loops', 'aliases' => [ 'loops', 'loops.so' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Transactional and marketing email platform for SaaS companies.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://loops.so', + '_ettic_otc_sub_purpose' => 'Transactional and marketing email platform for SaaS companies.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://loops.so', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Contact email addresses, names, user properties, message content, and engagement events.', + '_ettic_otc_sub_data_processed' => 'Contact email addresses, names, user properties, message content, and engagement events.', ], ], @@ -397,12 +397,12 @@ 'name' => 'Brevo', 'aliases' => [ 'brevo', 'sendinblue', 'send in blue' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Transactional and marketing email, SMS, and customer messaging platform.', - '_opentrust_sub_country' => 'FR', - '_opentrust_sub_website' => 'https://brevo.com', + '_ettic_otc_sub_purpose' => 'Transactional and marketing email, SMS, and customer messaging platform.', + '_ettic_otc_sub_country' => 'FR', + '_ettic_otc_sub_website' => 'https://brevo.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Contact email addresses, phone numbers, names, message content, and engagement events.', + '_ettic_otc_sub_data_processed' => 'Contact email addresses, phone numbers, names, message content, and engagement events.', ], ], @@ -410,12 +410,12 @@ 'name' => 'Mailchimp', 'aliases' => [ 'mailchimp', 'mail chimp', 'intuit mailchimp' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Marketing email and audience management platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://mailchimp.com', + '_ettic_otc_sub_purpose' => 'Marketing email and audience management platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://mailchimp.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Subscriber email addresses, names, audience segmentation data, message content, and engagement events.', + '_ettic_otc_sub_data_processed' => 'Subscriber email addresses, names, audience segmentation data, message content, and engagement events.', ], ], @@ -423,12 +423,12 @@ 'name' => 'Kit', 'aliases' => [ 'convertkit', 'convert kit', 'kit' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Email marketing platform for creators and publishers.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://kit.com', + '_ettic_otc_sub_purpose' => 'Email marketing platform for creators and publishers.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://kit.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Subscriber email addresses, names, tags, message content, and engagement events.', + '_ettic_otc_sub_data_processed' => 'Subscriber email addresses, names, tags, message content, and engagement events.', ], ], @@ -436,12 +436,12 @@ 'name' => 'Customer.io', 'aliases' => [ 'customer.io', 'customerio', 'customer io' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Customer messaging platform for email, SMS, and push notifications.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://customer.io', + '_ettic_otc_sub_purpose' => 'Customer messaging platform for email, SMS, and push notifications.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://customer.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Customer profiles, email addresses, behavioral events, message content, and engagement data.', + '_ettic_otc_sub_data_processed' => 'Customer profiles, email addresses, behavioral events, message content, and engagement data.', ], ], @@ -449,12 +449,12 @@ 'name' => 'Klaviyo', 'aliases' => [ 'klaviyo' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Marketing automation and customer data platform for email and SMS.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://klaviyo.com', + '_ettic_otc_sub_purpose' => 'Marketing automation and customer data platform for email and SMS.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://klaviyo.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Customer profiles, email addresses, phone numbers, purchase history, and engagement events.', + '_ettic_otc_sub_data_processed' => 'Customer profiles, email addresses, phone numbers, purchase history, and engagement events.', ], ], @@ -462,12 +462,12 @@ 'name' => 'Stripe', 'aliases' => [ 'stripe' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Payment processing and billing infrastructure.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://stripe.com', + '_ettic_otc_sub_purpose' => 'Payment processing and billing infrastructure.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://stripe.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Payment card details (tokenized), billing address, customer email, and transaction metadata.', + '_ettic_otc_sub_data_processed' => 'Payment card details (tokenized), billing address, customer email, and transaction metadata.', ], ], @@ -475,12 +475,12 @@ 'name' => 'Paddle', 'aliases' => [ 'paddle', 'paddle.com' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Merchant of record payment and subscription platform for software companies.', - '_opentrust_sub_country' => 'GB', - '_opentrust_sub_website' => 'https://paddle.com', + '_ettic_otc_sub_purpose' => 'Merchant of record payment and subscription platform for software companies.', + '_ettic_otc_sub_country' => 'GB', + '_ettic_otc_sub_website' => 'https://paddle.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Payment card details (tokenized), billing address, customer email, tax information, and transaction metadata.', + '_ettic_otc_sub_data_processed' => 'Payment card details (tokenized), billing address, customer email, tax information, and transaction metadata.', ], ], @@ -488,12 +488,12 @@ 'name' => 'Lemon Squeezy', 'aliases' => [ 'lemon squeezy', 'lemonsqueezy' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Merchant of record payment and subscription platform for digital products.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://lemonsqueezy.com', + '_ettic_otc_sub_purpose' => 'Merchant of record payment and subscription platform for digital products.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://lemonsqueezy.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Payment card details (tokenized), billing address, customer email, tax information, and transaction metadata.', + '_ettic_otc_sub_data_processed' => 'Payment card details (tokenized), billing address, customer email, tax information, and transaction metadata.', ], ], @@ -501,12 +501,12 @@ 'name' => 'Braintree', 'aliases' => [ 'braintree', 'paypal braintree' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Payment processing platform owned by PayPal.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://braintreepayments.com', + '_ettic_otc_sub_purpose' => 'Payment processing platform owned by PayPal.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://braintreepayments.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Payment card details (tokenized), billing address, customer email, and transaction metadata.', + '_ettic_otc_sub_data_processed' => 'Payment card details (tokenized), billing address, customer email, and transaction metadata.', ], ], @@ -514,12 +514,12 @@ 'name' => 'PayPal', 'aliases' => [ 'paypal', 'pay pal' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Online payment processing and digital wallet service.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://paypal.com', + '_ettic_otc_sub_purpose' => 'Online payment processing and digital wallet service.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://paypal.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Payer account identifiers, email addresses, billing address, and transaction metadata.', + '_ettic_otc_sub_data_processed' => 'Payer account identifiers, email addresses, billing address, and transaction metadata.', ], ], @@ -527,12 +527,12 @@ 'name' => 'Chargebee', 'aliases' => [ 'chargebee' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Subscription billing and revenue management platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://chargebee.com', + '_ettic_otc_sub_purpose' => 'Subscription billing and revenue management platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://chargebee.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Customer profiles, billing address, email, subscription data, and transaction metadata.', + '_ettic_otc_sub_data_processed' => 'Customer profiles, billing address, email, subscription data, and transaction metadata.', ], ], @@ -540,12 +540,12 @@ 'name' => 'Recurly', 'aliases' => [ 'recurly' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Subscription billing and revenue management platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://recurly.com', + '_ettic_otc_sub_purpose' => 'Subscription billing and revenue management platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://recurly.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Customer profiles, billing address, email, subscription data, and transaction metadata.', + '_ettic_otc_sub_data_processed' => 'Customer profiles, billing address, email, subscription data, and transaction metadata.', ], ], @@ -553,11 +553,11 @@ 'name' => 'Google Analytics', 'aliases' => [ 'google analytics', 'ga', 'ga4', 'universal analytics' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Web and app analytics platform.', - '_opentrust_sub_website' => 'https://analytics.google.com', + '_ettic_otc_sub_purpose' => 'Web and app analytics platform.', + '_ettic_otc_sub_website' => 'https://analytics.google.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Page views, user interactions, device and browser metadata, IP addresses, and pseudonymous user identifiers.', + '_ettic_otc_sub_data_processed' => 'Page views, user interactions, device and browser metadata, IP addresses, and pseudonymous user identifiers.', ], ], @@ -565,12 +565,12 @@ 'name' => 'PostHog', 'aliases' => [ 'posthog', 'post hog' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Product analytics, session replay, and feature flag platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://posthog.com', + '_ettic_otc_sub_purpose' => 'Product analytics, session replay, and feature flag platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://posthog.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Product usage events, user identifiers, session recordings, and device metadata.', + '_ettic_otc_sub_data_processed' => 'Product usage events, user identifiers, session recordings, and device metadata.', ], ], @@ -578,12 +578,12 @@ 'name' => 'Plausible Analytics', 'aliases' => [ 'plausible', 'plausible analytics' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Privacy-focused web analytics platform.', - '_opentrust_sub_country' => 'EE', - '_opentrust_sub_website' => 'https://plausible.io', + '_ettic_otc_sub_purpose' => 'Privacy-focused web analytics platform.', + '_ettic_otc_sub_country' => 'EE', + '_ettic_otc_sub_website' => 'https://plausible.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Aggregated page views, referrers, and anonymized device and browser metadata.', + '_ettic_otc_sub_data_processed' => 'Aggregated page views, referrers, and anonymized device and browser metadata.', ], ], @@ -591,11 +591,11 @@ 'name' => 'Fathom Analytics', 'aliases' => [ 'fathom', 'fathom analytics' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Privacy-focused web analytics platform.', - '_opentrust_sub_website' => 'https://usefathom.com', + '_ettic_otc_sub_purpose' => 'Privacy-focused web analytics platform.', + '_ettic_otc_sub_website' => 'https://usefathom.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Aggregated page views, referrers, and anonymized device and browser metadata.', + '_ettic_otc_sub_data_processed' => 'Aggregated page views, referrers, and anonymized device and browser metadata.', ], ], @@ -603,12 +603,12 @@ 'name' => 'Mixpanel', 'aliases' => [ 'mixpanel' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Product analytics platform for tracking user behavior.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://mixpanel.com', + '_ettic_otc_sub_purpose' => 'Product analytics platform for tracking user behavior.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://mixpanel.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Product usage events, user identifiers, user properties, and device metadata.', + '_ettic_otc_sub_data_processed' => 'Product usage events, user identifiers, user properties, and device metadata.', ], ], @@ -616,12 +616,12 @@ 'name' => 'Amplitude', 'aliases' => [ 'amplitude' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Product analytics platform for tracking user behavior.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://amplitude.com', + '_ettic_otc_sub_purpose' => 'Product analytics platform for tracking user behavior.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://amplitude.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Product usage events, user identifiers, user properties, and device metadata.', + '_ettic_otc_sub_data_processed' => 'Product usage events, user identifiers, user properties, and device metadata.', ], ], @@ -629,12 +629,12 @@ 'name' => 'Heap', 'aliases' => [ 'heap', 'heap analytics' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Product analytics platform with automatic event capture.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://heap.io', + '_ettic_otc_sub_purpose' => 'Product analytics platform with automatic event capture.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://heap.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Product usage events, user identifiers, user properties, and device metadata.', + '_ettic_otc_sub_data_processed' => 'Product usage events, user identifiers, user properties, and device metadata.', ], ], @@ -642,12 +642,12 @@ 'name' => 'Segment', 'aliases' => [ 'segment', 'twilio segment' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Customer data platform for collecting and routing analytics events.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://segment.com', + '_ettic_otc_sub_purpose' => 'Customer data platform for collecting and routing analytics events.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://segment.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Customer profiles, user identifiers, event data, and traits forwarded to downstream tools.', + '_ettic_otc_sub_data_processed' => 'Customer profiles, user identifiers, event data, and traits forwarded to downstream tools.', ], ], @@ -655,12 +655,12 @@ 'name' => 'RudderStack', 'aliases' => [ 'rudderstack', 'rudder stack' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Customer data platform for collecting and routing analytics events.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://rudderstack.com', + '_ettic_otc_sub_purpose' => 'Customer data platform for collecting and routing analytics events.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://rudderstack.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Customer profiles, user identifiers, event data, and traits forwarded to downstream tools.', + '_ettic_otc_sub_data_processed' => 'Customer profiles, user identifiers, event data, and traits forwarded to downstream tools.', ], ], @@ -668,12 +668,12 @@ 'name' => 'Intercom', 'aliases' => [ 'intercom' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Customer messaging and support platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://intercom.com', + '_ettic_otc_sub_purpose' => 'Customer messaging and support platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://intercom.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Customer contact details, conversation history, user attributes, and product usage events.', + '_ettic_otc_sub_data_processed' => 'Customer contact details, conversation history, user attributes, and product usage events.', ], ], @@ -681,12 +681,12 @@ 'name' => 'Zendesk', 'aliases' => [ 'zendesk' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Customer support ticketing and help desk platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://zendesk.com', + '_ettic_otc_sub_purpose' => 'Customer support ticketing and help desk platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://zendesk.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Customer contact details, support ticket content, conversation history, and attachments.', + '_ettic_otc_sub_data_processed' => 'Customer contact details, support ticket content, conversation history, and attachments.', ], ], @@ -694,12 +694,12 @@ 'name' => 'HubSpot', 'aliases' => [ 'hubspot', 'hub spot' ], 'fields' => [ - '_opentrust_sub_purpose' => 'CRM, marketing, sales, and customer service platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://hubspot.com', + '_ettic_otc_sub_purpose' => 'CRM, marketing, sales, and customer service platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://hubspot.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Contact details, company records, email correspondence, marketing engagement, and sales pipeline data.', + '_ettic_otc_sub_data_processed' => 'Contact details, company records, email correspondence, marketing engagement, and sales pipeline data.', ], ], @@ -707,12 +707,12 @@ 'name' => 'Front', 'aliases' => [ 'front', 'frontapp' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Shared inbox and customer communication platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://front.com', + '_ettic_otc_sub_purpose' => 'Shared inbox and customer communication platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://front.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Customer contact details, email and message content, conversation history, and attachments.', + '_ettic_otc_sub_data_processed' => 'Customer contact details, email and message content, conversation history, and attachments.', ], ], @@ -720,12 +720,12 @@ 'name' => 'Help Scout', 'aliases' => [ 'help scout', 'helpscout' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Customer support help desk and shared inbox platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://helpscout.com', + '_ettic_otc_sub_purpose' => 'Customer support help desk and shared inbox platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://helpscout.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Customer contact details, support ticket content, conversation history, and attachments.', + '_ettic_otc_sub_data_processed' => 'Customer contact details, support ticket content, conversation history, and attachments.', ], ], @@ -733,12 +733,12 @@ 'name' => 'Crisp', 'aliases' => [ 'crisp', 'crisp chat' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Customer messaging and live chat platform.', - '_opentrust_sub_country' => 'FR', - '_opentrust_sub_website' => 'https://crisp.chat', + '_ettic_otc_sub_purpose' => 'Customer messaging and live chat platform.', + '_ettic_otc_sub_country' => 'FR', + '_ettic_otc_sub_website' => 'https://crisp.chat', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Customer contact details, chat transcripts, user attributes, and conversation history.', + '_ettic_otc_sub_data_processed' => 'Customer contact details, chat transcripts, user attributes, and conversation history.', ], ], @@ -746,11 +746,11 @@ 'name' => 'Freshdesk', 'aliases' => [ 'freshdesk', 'fresh desk', 'freshworks' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Customer support ticketing and help desk platform.', - '_opentrust_sub_website' => 'https://freshworks.com/freshdesk', + '_ettic_otc_sub_purpose' => 'Customer support ticketing and help desk platform.', + '_ettic_otc_sub_website' => 'https://freshworks.com/freshdesk', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Customer contact details, support ticket content, conversation history, and attachments.', + '_ettic_otc_sub_data_processed' => 'Customer contact details, support ticket content, conversation history, and attachments.', ], ], @@ -758,12 +758,12 @@ 'name' => 'Pipedrive', 'aliases' => [ 'pipedrive' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Sales CRM and pipeline management platform.', - '_opentrust_sub_country' => 'EE', - '_opentrust_sub_website' => 'https://pipedrive.com', + '_ettic_otc_sub_purpose' => 'Sales CRM and pipeline management platform.', + '_ettic_otc_sub_country' => 'EE', + '_ettic_otc_sub_website' => 'https://pipedrive.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Contact details, company records, deal pipeline data, and email correspondence.', + '_ettic_otc_sub_data_processed' => 'Contact details, company records, deal pipeline data, and email correspondence.', ], ], @@ -771,12 +771,12 @@ 'name' => 'Salesforce', 'aliases' => [ 'salesforce', 'sfdc' ], 'fields' => [ - '_opentrust_sub_purpose' => 'CRM and enterprise cloud platform for sales, service, and marketing.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://salesforce.com', + '_ettic_otc_sub_purpose' => 'CRM and enterprise cloud platform for sales, service, and marketing.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://salesforce.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Contact details, company records, sales pipeline data, customer interactions, and case history.', + '_ettic_otc_sub_data_processed' => 'Contact details, company records, sales pipeline data, customer interactions, and case history.', ], ], @@ -784,12 +784,12 @@ 'name' => 'Auth0', 'aliases' => [ 'auth0', 'okta auth0' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Identity and access management platform for authentication.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://auth0.com', + '_ettic_otc_sub_purpose' => 'Identity and access management platform for authentication.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://auth0.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User credentials, email addresses, profile attributes, session tokens, and authentication logs.', + '_ettic_otc_sub_data_processed' => 'User credentials, email addresses, profile attributes, session tokens, and authentication logs.', ], ], @@ -797,12 +797,12 @@ 'name' => 'Clerk', 'aliases' => [ 'clerk', 'clerk.dev', 'clerk.com' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Authentication and user management platform for web and mobile apps.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://clerk.com', + '_ettic_otc_sub_purpose' => 'Authentication and user management platform for web and mobile apps.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://clerk.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User credentials, email addresses, phone numbers, profile attributes, and authentication logs.', + '_ettic_otc_sub_data_processed' => 'User credentials, email addresses, phone numbers, profile attributes, and authentication logs.', ], ], @@ -810,12 +810,12 @@ 'name' => 'WorkOS', 'aliases' => [ 'workos', 'work os' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Enterprise authentication, SSO, and directory sync platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://workos.com', + '_ettic_otc_sub_purpose' => 'Enterprise authentication, SSO, and directory sync platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://workos.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User credentials, email addresses, profile attributes, directory records, and authentication logs.', + '_ettic_otc_sub_data_processed' => 'User credentials, email addresses, profile attributes, directory records, and authentication logs.', ], ], @@ -823,12 +823,12 @@ 'name' => 'Stytch', 'aliases' => [ 'stytch' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Passwordless authentication and user management platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://stytch.com', + '_ettic_otc_sub_purpose' => 'Passwordless authentication and user management platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://stytch.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User credentials, email addresses, phone numbers, profile attributes, and authentication logs.', + '_ettic_otc_sub_data_processed' => 'User credentials, email addresses, phone numbers, profile attributes, and authentication logs.', ], ], @@ -836,12 +836,12 @@ 'name' => 'Descope', 'aliases' => [ 'descope' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Authentication and user management platform with visual flow builder.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://descope.com', + '_ettic_otc_sub_purpose' => 'Authentication and user management platform with visual flow builder.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://descope.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User credentials, email addresses, phone numbers, profile attributes, and authentication logs.', + '_ettic_otc_sub_data_processed' => 'User credentials, email addresses, phone numbers, profile attributes, and authentication logs.', ], ], @@ -849,11 +849,11 @@ 'name' => 'Firebase Authentication', 'aliases' => [ 'firebase auth', 'firebase authentication' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Authentication service from Google Firebase.', - '_opentrust_sub_website' => 'https://firebase.google.com/products/auth', + '_ettic_otc_sub_purpose' => 'Authentication service from Google Firebase.', + '_ettic_otc_sub_website' => 'https://firebase.google.com/products/auth', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User credentials, email addresses, phone numbers, profile attributes, and authentication logs.', + '_ettic_otc_sub_data_processed' => 'User credentials, email addresses, phone numbers, profile attributes, and authentication logs.', ], ], @@ -861,11 +861,11 @@ 'name' => 'Supabase', 'aliases' => [ 'supabase' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed Postgres database, authentication, storage, and backend platform.', - '_opentrust_sub_website' => 'https://supabase.com', + '_ettic_otc_sub_purpose' => 'Managed Postgres database, authentication, storage, and backend platform.', + '_ettic_otc_sub_website' => 'https://supabase.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application database contents, user credentials, uploaded files, and authentication logs.', + '_ettic_otc_sub_data_processed' => 'Application database contents, user credentials, uploaded files, and authentication logs.', ], ], @@ -873,11 +873,11 @@ 'name' => 'Firebase', 'aliases' => [ 'firebase', 'google firebase' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Google backend platform offering database, authentication, hosting, and analytics.', - '_opentrust_sub_website' => 'https://firebase.google.com', + '_ettic_otc_sub_purpose' => 'Google backend platform offering database, authentication, hosting, and analytics.', + '_ettic_otc_sub_website' => 'https://firebase.google.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application database contents, user credentials, uploaded files, and analytics events.', + '_ettic_otc_sub_data_processed' => 'Application database contents, user credentials, uploaded files, and analytics events.', ], ], @@ -885,11 +885,11 @@ 'name' => 'MongoDB Atlas', 'aliases' => [ 'mongodb atlas', 'mongo atlas', 'atlas' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed MongoDB database service.', - '_opentrust_sub_website' => 'https://mongodb.com/atlas', + '_ettic_otc_sub_purpose' => 'Managed MongoDB database service.', + '_ettic_otc_sub_website' => 'https://mongodb.com/atlas', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application database contents, query logs, and backups.', + '_ettic_otc_sub_data_processed' => 'Application database contents, query logs, and backups.', ], ], @@ -897,12 +897,12 @@ 'name' => 'PlanetScale', 'aliases' => [ 'planetscale', 'planet scale' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed MySQL database platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://planetscale.com', + '_ettic_otc_sub_purpose' => 'Managed MySQL database platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://planetscale.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application database contents, query logs, and backups.', + '_ettic_otc_sub_data_processed' => 'Application database contents, query logs, and backups.', ], ], @@ -910,12 +910,12 @@ 'name' => 'Neon', 'aliases' => [ 'neon', 'neon.tech', 'neon database' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed serverless Postgres database platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://neon.tech', + '_ettic_otc_sub_purpose' => 'Managed serverless Postgres database platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://neon.tech', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application database contents, query logs, and backups.', + '_ettic_otc_sub_data_processed' => 'Application database contents, query logs, and backups.', ], ], @@ -923,11 +923,11 @@ 'name' => 'Upstash', 'aliases' => [ 'upstash' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed serverless Redis, Kafka, and vector database platform.', - '_opentrust_sub_website' => 'https://upstash.com', + '_ettic_otc_sub_purpose' => 'Managed serverless Redis, Kafka, and vector database platform.', + '_ettic_otc_sub_website' => 'https://upstash.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application cache data, queue messages, and database contents.', + '_ettic_otc_sub_data_processed' => 'Application cache data, queue messages, and database contents.', ], ], @@ -935,11 +935,11 @@ 'name' => 'Turso', 'aliases' => [ 'turso' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed SQLite-compatible edge database platform.', - '_opentrust_sub_website' => 'https://turso.tech', + '_ettic_otc_sub_purpose' => 'Managed SQLite-compatible edge database platform.', + '_ettic_otc_sub_website' => 'https://turso.tech', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application database contents, query logs, and backups.', + '_ettic_otc_sub_data_processed' => 'Application database contents, query logs, and backups.', ], ], @@ -947,12 +947,12 @@ 'name' => 'OpenAI', 'aliases' => [ 'openai', 'open ai', 'chatgpt api' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Large language model API provider.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://openai.com', + '_ettic_otc_sub_purpose' => 'Large language model API provider.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://openai.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Prompt content, completions, and API request metadata submitted to model endpoints.', + '_ettic_otc_sub_data_processed' => 'Prompt content, completions, and API request metadata submitted to model endpoints.', ], ], @@ -960,12 +960,12 @@ 'name' => 'Anthropic', 'aliases' => [ 'anthropic', 'claude' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Large language model API provider, maker of Claude.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://anthropic.com', + '_ettic_otc_sub_purpose' => 'Large language model API provider, maker of Claude.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://anthropic.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Prompt content, completions, and API request metadata submitted to model endpoints.', + '_ettic_otc_sub_data_processed' => 'Prompt content, completions, and API request metadata submitted to model endpoints.', ], ], @@ -973,11 +973,11 @@ 'name' => 'Google AI', 'aliases' => [ 'google ai', 'gemini', 'gemini api', 'google generative ai' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Large language model API provider for Gemini models.', - '_opentrust_sub_website' => 'https://ai.google.dev', + '_ettic_otc_sub_purpose' => 'Large language model API provider for Gemini models.', + '_ettic_otc_sub_website' => 'https://ai.google.dev', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Prompt content, completions, and API request metadata submitted to model endpoints.', + '_ettic_otc_sub_data_processed' => 'Prompt content, completions, and API request metadata submitted to model endpoints.', ], ], @@ -985,12 +985,12 @@ 'name' => 'Mistral AI', 'aliases' => [ 'mistral', 'mistral ai' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Large language model API provider.', - '_opentrust_sub_country' => 'FR', - '_opentrust_sub_website' => 'https://mistral.ai', + '_ettic_otc_sub_purpose' => 'Large language model API provider.', + '_ettic_otc_sub_country' => 'FR', + '_ettic_otc_sub_website' => 'https://mistral.ai', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Prompt content, completions, and API request metadata submitted to model endpoints.', + '_ettic_otc_sub_data_processed' => 'Prompt content, completions, and API request metadata submitted to model endpoints.', ], ], @@ -998,12 +998,12 @@ 'name' => 'Perplexity', 'aliases' => [ 'perplexity', 'perplexity ai' ], 'fields' => [ - '_opentrust_sub_purpose' => 'AI-powered search and language model API provider.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://perplexity.ai', + '_ettic_otc_sub_purpose' => 'AI-powered search and language model API provider.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://perplexity.ai', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Prompt content, search queries, completions, and API request metadata.', + '_ettic_otc_sub_data_processed' => 'Prompt content, search queries, completions, and API request metadata.', ], ], @@ -1011,11 +1011,11 @@ 'name' => 'OpenRouter', 'aliases' => [ 'openrouter', 'open router' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Unified API gateway for accessing multiple large language model providers.', - '_opentrust_sub_website' => 'https://openrouter.ai', + '_ettic_otc_sub_purpose' => 'Unified API gateway for accessing multiple large language model providers.', + '_ettic_otc_sub_website' => 'https://openrouter.ai', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Prompt content, completions, and API request metadata routed to upstream model providers.', + '_ettic_otc_sub_data_processed' => 'Prompt content, completions, and API request metadata routed to upstream model providers.', ], ], @@ -1023,12 +1023,12 @@ 'name' => 'Replicate', 'aliases' => [ 'replicate', 'replicate.com' ], 'fields' => [ - '_opentrust_sub_purpose' => 'API platform for running open-source machine learning models.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://replicate.com', + '_ettic_otc_sub_purpose' => 'API platform for running open-source machine learning models.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://replicate.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Model inputs (including images, audio, and text), outputs, and API request metadata.', + '_ettic_otc_sub_data_processed' => 'Model inputs (including images, audio, and text), outputs, and API request metadata.', ], ], @@ -1036,12 +1036,12 @@ 'name' => 'Slack', 'aliases' => [ 'slack' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Team messaging and collaboration platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://slack.com', + '_ettic_otc_sub_purpose' => 'Team messaging and collaboration platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://slack.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User profiles, message content, channel membership, and uploaded files.', + '_ettic_otc_sub_data_processed' => 'User profiles, message content, channel membership, and uploaded files.', ], ], @@ -1049,12 +1049,12 @@ 'name' => 'Linear', 'aliases' => [ 'linear', 'linear.app' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Issue tracking and project management tool for software teams.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://linear.app', + '_ettic_otc_sub_purpose' => 'Issue tracking and project management tool for software teams.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://linear.app', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User profiles, issue content, project data, and comments.', + '_ettic_otc_sub_data_processed' => 'User profiles, issue content, project data, and comments.', ], ], @@ -1062,12 +1062,12 @@ 'name' => 'Notion', 'aliases' => [ 'notion', 'notion.so' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Collaborative workspace for notes, documents, and databases.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://notion.so', + '_ettic_otc_sub_purpose' => 'Collaborative workspace for notes, documents, and databases.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://notion.so', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User profiles, document content, database records, and uploaded files.', + '_ettic_otc_sub_data_processed' => 'User profiles, document content, database records, and uploaded files.', ], ], @@ -1075,12 +1075,12 @@ 'name' => 'Asana', 'aliases' => [ 'asana' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Work and project management platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://asana.com', + '_ettic_otc_sub_purpose' => 'Work and project management platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://asana.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User profiles, task content, project data, and comments.', + '_ettic_otc_sub_data_processed' => 'User profiles, task content, project data, and comments.', ], ], @@ -1088,11 +1088,11 @@ 'name' => 'Trello', 'aliases' => [ 'trello', 'atlassian trello' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Kanban-style project management tool.', - '_opentrust_sub_website' => 'https://trello.com', + '_ettic_otc_sub_purpose' => 'Kanban-style project management tool.', + '_ettic_otc_sub_website' => 'https://trello.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User profiles, card content, board data, and attachments.', + '_ettic_otc_sub_data_processed' => 'User profiles, card content, board data, and attachments.', ], ], @@ -1100,12 +1100,12 @@ 'name' => 'Zoom', 'aliases' => [ 'zoom', 'zoom video' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Video conferencing and communications platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://zoom.us', + '_ettic_otc_sub_purpose' => 'Video conferencing and communications platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://zoom.us', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User profiles, meeting metadata, call recordings, and chat transcripts.', + '_ettic_otc_sub_data_processed' => 'User profiles, meeting metadata, call recordings, and chat transcripts.', ], ], @@ -1113,11 +1113,11 @@ 'name' => 'Google Workspace', 'aliases' => [ 'google workspace', 'gsuite', 'g suite' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Productivity suite including email, documents, calendar, and storage.', - '_opentrust_sub_website' => 'https://workspace.google.com', + '_ettic_otc_sub_purpose' => 'Productivity suite including email, documents, calendar, and storage.', + '_ettic_otc_sub_website' => 'https://workspace.google.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Employee email, documents, calendar events, contacts, and files stored in Drive.', + '_ettic_otc_sub_data_processed' => 'Employee email, documents, calendar events, contacts, and files stored in Drive.', ], ], @@ -1125,11 +1125,11 @@ 'name' => 'Microsoft 365', 'aliases' => [ 'microsoft 365', 'm365', 'office 365', 'o365' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Productivity suite including email, documents, calendar, and storage.', - '_opentrust_sub_website' => 'https://microsoft.com/microsoft-365', + '_ettic_otc_sub_purpose' => 'Productivity suite including email, documents, calendar, and storage.', + '_ettic_otc_sub_website' => 'https://microsoft.com/microsoft-365', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Employee email, documents, calendar events, contacts, and files stored in OneDrive or SharePoint.', + '_ettic_otc_sub_data_processed' => 'Employee email, documents, calendar events, contacts, and files stored in OneDrive or SharePoint.', ], ], @@ -1137,12 +1137,12 @@ 'name' => 'GitHub', 'aliases' => [ 'github', 'git hub' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Source code hosting and collaboration platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://github.com', + '_ettic_otc_sub_purpose' => 'Source code hosting and collaboration platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://github.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Source code, issues, pull requests, user profiles, and CI artifacts.', + '_ettic_otc_sub_data_processed' => 'Source code, issues, pull requests, user profiles, and CI artifacts.', ], ], @@ -1150,12 +1150,12 @@ 'name' => 'GitLab', 'aliases' => [ 'gitlab', 'git lab' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Source code hosting, CI/CD, and DevOps platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://about.gitlab.com', + '_ettic_otc_sub_purpose' => 'Source code hosting, CI/CD, and DevOps platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://about.gitlab.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Source code, issues, merge requests, user profiles, and CI artifacts.', + '_ettic_otc_sub_data_processed' => 'Source code, issues, merge requests, user profiles, and CI artifacts.', ], ], @@ -1163,11 +1163,11 @@ 'name' => 'Bitbucket', 'aliases' => [ 'bitbucket', 'atlassian bitbucket' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Source code hosting and collaboration platform from Atlassian.', - '_opentrust_sub_website' => 'https://bitbucket.org', + '_ettic_otc_sub_purpose' => 'Source code hosting and collaboration platform from Atlassian.', + '_ettic_otc_sub_website' => 'https://bitbucket.org', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Source code, issues, pull requests, user profiles, and CI artifacts.', + '_ettic_otc_sub_data_processed' => 'Source code, issues, pull requests, user profiles, and CI artifacts.', ], ], @@ -1175,12 +1175,12 @@ 'name' => 'CircleCI', 'aliases' => [ 'circleci', 'circle ci' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Continuous integration and delivery platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://circleci.com', + '_ettic_otc_sub_purpose' => 'Continuous integration and delivery platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://circleci.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Source code, build logs, environment variables, and CI artifacts.', + '_ettic_otc_sub_data_processed' => 'Source code, build logs, environment variables, and CI artifacts.', ], ], @@ -1188,12 +1188,12 @@ 'name' => 'Buildkite', 'aliases' => [ 'buildkite', 'build kite' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Continuous integration and delivery platform with self-hosted agents.', - '_opentrust_sub_country' => 'AU', - '_opentrust_sub_website' => 'https://buildkite.com', + '_ettic_otc_sub_purpose' => 'Continuous integration and delivery platform with self-hosted agents.', + '_ettic_otc_sub_country' => 'AU', + '_ettic_otc_sub_website' => 'https://buildkite.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Build metadata, pipeline configuration, logs, and job artifacts.', + '_ettic_otc_sub_data_processed' => 'Build metadata, pipeline configuration, logs, and job artifacts.', ], ], @@ -1201,12 +1201,12 @@ 'name' => 'OneSignal', 'aliases' => [ 'onesignal', 'one signal' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Push notification and customer messaging platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://onesignal.com', + '_ettic_otc_sub_purpose' => 'Push notification and customer messaging platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://onesignal.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Device tokens, user identifiers, subscription preferences, and notification content.', + '_ettic_otc_sub_data_processed' => 'Device tokens, user identifiers, subscription preferences, and notification content.', ], ], @@ -1214,12 +1214,12 @@ 'name' => 'Knock', 'aliases' => [ 'knock', 'knock.app' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Notification infrastructure for product messaging across channels.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://knock.app', + '_ettic_otc_sub_purpose' => 'Notification infrastructure for product messaging across channels.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://knock.app', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User profiles, notification content, delivery metadata, and channel preferences.', + '_ettic_otc_sub_data_processed' => 'User profiles, notification content, delivery metadata, and channel preferences.', ], ], @@ -1227,12 +1227,12 @@ 'name' => 'Courier', 'aliases' => [ 'courier', 'courier.com' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Notification infrastructure for product messaging across channels.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://courier.com', + '_ettic_otc_sub_purpose' => 'Notification infrastructure for product messaging across channels.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://courier.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User profiles, notification content, delivery metadata, and channel preferences.', + '_ettic_otc_sub_data_processed' => 'User profiles, notification content, delivery metadata, and channel preferences.', ], ], @@ -1240,12 +1240,12 @@ 'name' => 'Cloudinary', 'aliases' => [ 'cloudinary' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Media management, image and video optimization, and delivery platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://cloudinary.com', + '_ettic_otc_sub_purpose' => 'Media management, image and video optimization, and delivery platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://cloudinary.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Uploaded images, videos, and associated metadata.', + '_ettic_otc_sub_data_processed' => 'Uploaded images, videos, and associated metadata.', ], ], @@ -1253,12 +1253,12 @@ 'name' => 'imgix', 'aliases' => [ 'imgix' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Real-time image processing and delivery platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://imgix.com', + '_ettic_otc_sub_purpose' => 'Real-time image processing and delivery platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://imgix.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Source images and associated metadata processed for delivery.', + '_ettic_otc_sub_data_processed' => 'Source images and associated metadata processed for delivery.', ], ], @@ -1266,11 +1266,11 @@ 'name' => 'Uploadcare', 'aliases' => [ 'uploadcare', 'upload care' ], 'fields' => [ - '_opentrust_sub_purpose' => 'File upload, storage, and media processing platform.', - '_opentrust_sub_website' => 'https://uploadcare.com', + '_ettic_otc_sub_purpose' => 'File upload, storage, and media processing platform.', + '_ettic_otc_sub_website' => 'https://uploadcare.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Uploaded files, images, videos, and associated metadata.', + '_ettic_otc_sub_data_processed' => 'Uploaded files, images, videos, and associated metadata.', ], ], @@ -1278,12 +1278,12 @@ 'name' => 'Bunny.net', 'aliases' => [ 'bunny', 'bunny.net', 'bunnycdn', 'bunny cdn' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Content delivery network and edge storage platform.', - '_opentrust_sub_country' => 'SI', - '_opentrust_sub_website' => 'https://bunny.net', + '_ettic_otc_sub_purpose' => 'Content delivery network and edge storage platform.', + '_ettic_otc_sub_country' => 'SI', + '_ettic_otc_sub_website' => 'https://bunny.net', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'HTTP request metadata, IP addresses, and cached content served to end users.', + '_ettic_otc_sub_data_processed' => 'HTTP request metadata, IP addresses, and cached content served to end users.', ], ], @@ -1291,12 +1291,12 @@ 'name' => 'Twilio', 'aliases' => [ 'twilio' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Communications API platform for SMS, voice, and messaging.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://twilio.com', + '_ettic_otc_sub_purpose' => 'Communications API platform for SMS, voice, and messaging.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://twilio.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Phone numbers, message content, call metadata, and delivery events.', + '_ettic_otc_sub_data_processed' => 'Phone numbers, message content, call metadata, and delivery events.', ], ], @@ -1304,12 +1304,12 @@ 'name' => 'Algolia', 'aliases' => [ 'algolia' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Hosted search and discovery API platform.', - '_opentrust_sub_country' => 'FR', - '_opentrust_sub_website' => 'https://algolia.com', + '_ettic_otc_sub_purpose' => 'Hosted search and discovery API platform.', + '_ettic_otc_sub_country' => 'FR', + '_ettic_otc_sub_website' => 'https://algolia.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Indexed content, search queries, and analytics events from end users.', + '_ettic_otc_sub_data_processed' => 'Indexed content, search queries, and analytics events from end users.', ], ], @@ -1317,11 +1317,11 @@ 'name' => 'Typesense', 'aliases' => [ 'typesense', 'typesense cloud' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Open-source search engine with managed cloud hosting.', - '_opentrust_sub_website' => 'https://typesense.org', + '_ettic_otc_sub_purpose' => 'Open-source search engine with managed cloud hosting.', + '_ettic_otc_sub_website' => 'https://typesense.org', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Indexed content and search queries from end users.', + '_ettic_otc_sub_data_processed' => 'Indexed content and search queries from end users.', ], ], @@ -1329,12 +1329,12 @@ 'name' => 'Meilisearch', 'aliases' => [ 'meilisearch', 'meili search', 'meili' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Open-source search engine with managed cloud hosting.', - '_opentrust_sub_country' => 'FR', - '_opentrust_sub_website' => 'https://meilisearch.com', + '_ettic_otc_sub_purpose' => 'Open-source search engine with managed cloud hosting.', + '_ettic_otc_sub_country' => 'FR', + '_ettic_otc_sub_website' => 'https://meilisearch.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Indexed content and search queries from end users.', + '_ettic_otc_sub_data_processed' => 'Indexed content and search queries from end users.', ], ], @@ -1342,12 +1342,12 @@ 'name' => 'Figma', 'aliases' => [ 'figma' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Collaborative interface design and prototyping platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://figma.com', + '_ettic_otc_sub_purpose' => 'Collaborative interface design and prototyping platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://figma.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User profiles, design files, comments, and collaboration metadata.', + '_ettic_otc_sub_data_processed' => 'User profiles, design files, comments, and collaboration metadata.', ], ], @@ -1355,12 +1355,12 @@ 'name' => 'Canva', 'aliases' => [ 'canva' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Online graphic design and publishing platform.', - '_opentrust_sub_country' => 'AU', - '_opentrust_sub_website' => 'https://canva.com', + '_ettic_otc_sub_purpose' => 'Online graphic design and publishing platform.', + '_ettic_otc_sub_country' => 'AU', + '_ettic_otc_sub_website' => 'https://canva.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User profiles, design files, uploaded assets, and collaboration metadata.', + '_ettic_otc_sub_data_processed' => 'User profiles, design files, uploaded assets, and collaboration metadata.', ], ], @@ -1368,12 +1368,12 @@ 'name' => 'Dropbox', 'aliases' => [ 'dropbox', 'drop box' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Cloud file storage and sharing platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://dropbox.com', + '_ettic_otc_sub_purpose' => 'Cloud file storage and sharing platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://dropbox.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Uploaded files, folder metadata, sharing links, and user profiles.', + '_ettic_otc_sub_data_processed' => 'Uploaded files, folder metadata, sharing links, and user profiles.', ], ], @@ -1381,12 +1381,12 @@ 'name' => 'Box', 'aliases' => [ 'box', 'box.com' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Cloud content management and file sharing platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://box.com', + '_ettic_otc_sub_purpose' => 'Cloud content management and file sharing platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://box.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Uploaded files, folder metadata, sharing links, and user profiles.', + '_ettic_otc_sub_data_processed' => 'Uploaded files, folder metadata, sharing links, and user profiles.', ], ], @@ -1394,12 +1394,12 @@ 'name' => 'Automattic', 'aliases' => [ 'automattic', 'automattic inc' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Parent company operating WordPress.com, Jetpack, Akismet, WooCommerce.com, and Tumblr.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://automattic.com', + '_ettic_otc_sub_purpose' => 'Parent company operating WordPress.com, Jetpack, Akismet, WooCommerce.com, and Tumblr.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://automattic.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Site content, visitor metadata, comments, backups, and account information.', + '_ettic_otc_sub_data_processed' => 'Site content, visitor metadata, comments, backups, and account information.', ], ], @@ -1407,12 +1407,12 @@ 'name' => 'Jetpack', 'aliases' => [ 'jetpack', 'jetpack.com' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Security, performance, backups, site stats, and content delivery for WordPress sites.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://jetpack.com', + '_ettic_otc_sub_purpose' => 'Security, performance, backups, site stats, and content delivery for WordPress sites.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://jetpack.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Site content, visitor metadata, comments, backup archives, and usage analytics from the connected WordPress site.', + '_ettic_otc_sub_data_processed' => 'Site content, visitor metadata, comments, backup archives, and usage analytics from the connected WordPress site.', ], ], @@ -1420,12 +1420,12 @@ 'name' => 'Akismet', 'aliases' => [ 'akismet', 'akismet anti-spam' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Spam detection for comments and form submissions on WordPress sites.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://akismet.com', + '_ettic_otc_sub_purpose' => 'Spam detection for comments and form submissions on WordPress sites.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://akismet.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Comment content, author names, email addresses, IP addresses, and user agent strings submitted for spam classification.', + '_ettic_otc_sub_data_processed' => 'Comment content, author names, email addresses, IP addresses, and user agent strings submitted for spam classification.', ], ], @@ -1433,12 +1433,12 @@ 'name' => 'WordPress.com', 'aliases' => [ 'wordpress.com', 'wordpress com', 'wp.com', 'wpcom' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed WordPress hosting, publishing, and site management service operated by Automattic.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://wordpress.com', + '_ettic_otc_sub_purpose' => 'Managed WordPress hosting, publishing, and site management service operated by Automattic.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://wordpress.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Site content, media uploads, visitor analytics, comments, and author account information.', + '_ettic_otc_sub_data_processed' => 'Site content, media uploads, visitor analytics, comments, and author account information.', ], ], @@ -1446,12 +1446,12 @@ 'name' => 'Meta', 'aliases' => [ 'meta', 'meta platforms', 'facebook', 'instagram', 'whatsapp', 'facebook business' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Social platform, advertising, and business tools from Meta, covering Facebook, Instagram, and WhatsApp.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://about.meta.com', + '_ettic_otc_sub_purpose' => 'Social platform, advertising, and business tools from Meta, covering Facebook, Instagram, and WhatsApp.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://about.meta.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Advertising events, custom audience data, Meta Pixel and Conversions API events, and authentication data when Facebook Login is used.', + '_ettic_otc_sub_data_processed' => 'Advertising events, custom audience data, Meta Pixel and Conversions API events, and authentication data when Facebook Login is used.', ], ], @@ -1459,12 +1459,12 @@ 'name' => 'MOSA Cloud', 'aliases' => [ 'mosa', 'mosa cloud', 'mosa.cloud', 'mosacloud' ], 'fields' => [ - '_opentrust_sub_purpose' => 'EU-based productivity suite with documents, file storage, email, and video meetings, built on open-source infrastructure.', - '_opentrust_sub_country' => 'NL', - '_opentrust_sub_website' => 'https://mosa.cloud', + '_ettic_otc_sub_purpose' => 'EU-based productivity suite with documents, file storage, email, and video meetings, built on open-source infrastructure.', + '_ettic_otc_sub_country' => 'NL', + '_ettic_otc_sub_website' => 'https://mosa.cloud', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Documents, spreadsheets, uploaded files, email messages, meeting recordings and transcripts, and team communications.', + '_ettic_otc_sub_data_processed' => 'Documents, spreadsheets, uploaded files, email messages, meeting recordings and transcripts, and team communications.', ], ], @@ -1474,12 +1474,12 @@ 'name' => 'WP Engine', 'aliases' => [ 'wpengine', 'wp engine' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed WordPress hosting and site infrastructure.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://wpengine.com', + '_ettic_otc_sub_purpose' => 'Managed WordPress hosting and site infrastructure.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://wpengine.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Website files, database contents, visitor IP addresses, server logs, and account billing information.', + '_ettic_otc_sub_data_processed' => 'Website files, database contents, visitor IP addresses, server logs, and account billing information.', ], ], @@ -1487,12 +1487,12 @@ 'name' => 'Kinsta', 'aliases' => [ 'kinsta' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed WordPress and application hosting built on Google Cloud.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://kinsta.com', + '_ettic_otc_sub_purpose' => 'Managed WordPress and application hosting built on Google Cloud.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://kinsta.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Website files, database contents, visitor IP addresses, access logs, and account billing information.', + '_ettic_otc_sub_data_processed' => 'Website files, database contents, visitor IP addresses, access logs, and account billing information.', ], ], @@ -1500,12 +1500,12 @@ 'name' => 'Pantheon', 'aliases' => [ 'pantheon', 'getpantheon' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed WordPress and Drupal website operations platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://pantheon.io', + '_ettic_otc_sub_purpose' => 'Managed WordPress and Drupal website operations platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://pantheon.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Website codebase, database contents, visitor request logs, and customer account details.', + '_ettic_otc_sub_data_processed' => 'Website codebase, database contents, visitor request logs, and customer account details.', ], ], @@ -1513,12 +1513,12 @@ 'name' => 'Pressable', 'aliases' => [ 'pressable', 'automattic pressable' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed WordPress hosting operated by Automattic.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://pressable.com', + '_ettic_otc_sub_purpose' => 'Managed WordPress hosting operated by Automattic.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://pressable.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Website files, database contents, visitor IP addresses, access logs, and billing details.', + '_ettic_otc_sub_data_processed' => 'Website files, database contents, visitor IP addresses, access logs, and billing details.', ], ], @@ -1526,11 +1526,11 @@ 'name' => 'SiteGround', 'aliases' => [ 'siteground', 'site ground' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Shared, cloud, and managed WordPress hosting services.', - '_opentrust_sub_website' => 'https://siteground.com', + '_ettic_otc_sub_purpose' => 'Shared, cloud, and managed WordPress hosting services.', + '_ettic_otc_sub_website' => 'https://siteground.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Website files, database contents, visitor IP addresses, server logs, and customer account information.', + '_ettic_otc_sub_data_processed' => 'Website files, database contents, visitor IP addresses, server logs, and customer account information.', ], ], @@ -1538,11 +1538,11 @@ 'name' => 'Cloudways', 'aliases' => [ 'cloudways' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed cloud hosting platform for web applications and WordPress.', - '_opentrust_sub_website' => 'https://cloudways.com', + '_ettic_otc_sub_purpose' => 'Managed cloud hosting platform for web applications and WordPress.', + '_ettic_otc_sub_website' => 'https://cloudways.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Website files, database contents, visitor logs, and customer account and billing details.', + '_ettic_otc_sub_data_processed' => 'Website files, database contents, visitor logs, and customer account and billing details.', ], ], @@ -1550,12 +1550,12 @@ 'name' => 'Flywheel', 'aliases' => [ 'flywheel', 'getflywheel' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed WordPress hosting for designers and agencies, owned by WP Engine.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://getflywheel.com', + '_ettic_otc_sub_purpose' => 'Managed WordPress hosting for designers and agencies, owned by WP Engine.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://getflywheel.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Website files, database contents, visitor IP addresses, access logs, and account billing information.', + '_ettic_otc_sub_data_processed' => 'Website files, database contents, visitor IP addresses, access logs, and account billing information.', ], ], @@ -1563,12 +1563,12 @@ 'name' => 'WooCommerce.com', 'aliases' => [ 'woocommerce', 'woo' ], 'fields' => [ - '_opentrust_sub_purpose' => 'WooCommerce extension marketplace and account services operated by Automattic.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://woocommerce.com', + '_ettic_otc_sub_purpose' => 'WooCommerce extension marketplace and account services operated by Automattic.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://woocommerce.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Customer account details, license keys, purchase history, and billing information.', + '_ettic_otc_sub_data_processed' => 'Customer account details, license keys, purchase history, and billing information.', ], ], @@ -1578,12 +1578,12 @@ 'name' => 'Bugsnag', 'aliases' => [ 'bugsnag', 'smartbear bugsnag' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Error monitoring and application stability reporting.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://bugsnag.com', + '_ettic_otc_sub_purpose' => 'Error monitoring and application stability reporting.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://bugsnag.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application error stack traces, user identifiers, device and browser metadata, and request context.', + '_ettic_otc_sub_data_processed' => 'Application error stack traces, user identifiers, device and browser metadata, and request context.', ], ], @@ -1591,12 +1591,12 @@ 'name' => 'Rollbar', 'aliases' => [ 'rollbar' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Error tracking and real-time exception monitoring.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://rollbar.com', + '_ettic_otc_sub_purpose' => 'Error tracking and real-time exception monitoring.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://rollbar.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application error stack traces, user identifiers, environment metadata, and request payloads.', + '_ettic_otc_sub_data_processed' => 'Application error stack traces, user identifiers, environment metadata, and request payloads.', ], ], @@ -1604,12 +1604,12 @@ 'name' => 'AppSignal', 'aliases' => [ 'appsignal' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Application performance monitoring and error tracking.', - '_opentrust_sub_country' => 'NL', - '_opentrust_sub_website' => 'https://appsignal.com', + '_ettic_otc_sub_purpose' => 'Application performance monitoring and error tracking.', + '_ettic_otc_sub_country' => 'NL', + '_ettic_otc_sub_website' => 'https://appsignal.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Performance metrics, error stack traces, request metadata, and user identifiers.', + '_ettic_otc_sub_data_processed' => 'Performance metrics, error stack traces, request metadata, and user identifiers.', ], ], @@ -1617,12 +1617,12 @@ 'name' => 'Raygun', 'aliases' => [ 'raygun' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Crash reporting, real user monitoring, and application performance monitoring.', - '_opentrust_sub_country' => 'NZ', - '_opentrust_sub_website' => 'https://raygun.com', + '_ettic_otc_sub_purpose' => 'Crash reporting, real user monitoring, and application performance monitoring.', + '_ettic_otc_sub_country' => 'NZ', + '_ettic_otc_sub_website' => 'https://raygun.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Error diagnostics, session traces, user identifiers, and browser and device metadata.', + '_ettic_otc_sub_data_processed' => 'Error diagnostics, session traces, user identifiers, and browser and device metadata.', ], ], @@ -1630,12 +1630,12 @@ 'name' => 'Pingdom', 'aliases' => [ 'pingdom', 'solarwinds pingdom' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Website uptime, page speed, and synthetic transaction monitoring.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://pingdom.com', + '_ettic_otc_sub_purpose' => 'Website uptime, page speed, and synthetic transaction monitoring.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://pingdom.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Monitored URLs, response timing metrics, and alert contact details.', + '_ettic_otc_sub_data_processed' => 'Monitored URLs, response timing metrics, and alert contact details.', ], ], @@ -1643,12 +1643,12 @@ 'name' => 'UptimeRobot', 'aliases' => [ 'uptimerobot', 'uptime robot' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Website and service uptime monitoring with alerting.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://uptimerobot.com', + '_ettic_otc_sub_purpose' => 'Website and service uptime monitoring with alerting.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://uptimerobot.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Monitored URLs, response status, latency metrics, and alert contact details.', + '_ettic_otc_sub_data_processed' => 'Monitored URLs, response status, latency metrics, and alert contact details.', ], ], @@ -1656,12 +1656,12 @@ 'name' => 'Statuspage', 'aliases' => [ 'statuspage', 'atlassian statuspage' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Hosted status pages and incident communication for services.', - '_opentrust_sub_country' => 'AU', - '_opentrust_sub_website' => 'https://atlassian.com/software/statuspage', + '_ettic_otc_sub_purpose' => 'Hosted status pages and incident communication for services.', + '_ettic_otc_sub_country' => 'AU', + '_ettic_otc_sub_website' => 'https://atlassian.com/software/statuspage', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Subscriber email addresses, incident notes, component statuses, and administrator account details.', + '_ettic_otc_sub_data_processed' => 'Subscriber email addresses, incident notes, component statuses, and administrator account details.', ], ], @@ -1669,12 +1669,12 @@ 'name' => 'Highlight.io', 'aliases' => [ 'highlight', 'highlight.io' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Session replay, error monitoring, and application observability.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://highlight.io', + '_ettic_otc_sub_purpose' => 'Session replay, error monitoring, and application observability.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://highlight.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Session recordings, DOM events, console logs, error traces, and user identifiers.', + '_ettic_otc_sub_data_processed' => 'Session recordings, DOM events, console logs, error traces, and user identifiers.', ], ], @@ -1682,12 +1682,12 @@ 'name' => 'Loggly', 'aliases' => [ 'loggly', 'solarwinds loggly' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Cloud-based log aggregation and analysis.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://loggly.com', + '_ettic_otc_sub_purpose' => 'Cloud-based log aggregation and analysis.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://loggly.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application and server log events, request metadata, and any identifiers contained in logs.', + '_ettic_otc_sub_data_processed' => 'Application and server log events, request metadata, and any identifiers contained in logs.', ], ], @@ -1695,12 +1695,12 @@ 'name' => 'Papertrail', 'aliases' => [ 'papertrail', 'solarwinds papertrail' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Cloud-hosted log management and live tail for servers and apps.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://papertrail.com', + '_ettic_otc_sub_purpose' => 'Cloud-hosted log management and live tail for servers and apps.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://papertrail.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Syslog and application log events, hostnames, and any identifiers included in log lines.', + '_ettic_otc_sub_data_processed' => 'Syslog and application log events, hostnames, and any identifiers included in log lines.', ], ], @@ -1710,12 +1710,12 @@ 'name' => 'ActiveCampaign', 'aliases' => [ 'activecampaign', 'active campaign' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Email marketing, marketing automation, and sales CRM.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://activecampaign.com', + '_ettic_otc_sub_purpose' => 'Email marketing, marketing automation, and sales CRM.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://activecampaign.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Contact names, email addresses, engagement history, tags, and campaign interaction data.', + '_ettic_otc_sub_data_processed' => 'Contact names, email addresses, engagement history, tags, and campaign interaction data.', ], ], @@ -1723,12 +1723,12 @@ 'name' => 'MailerLite', 'aliases' => [ 'mailerlite', 'mailer lite' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Email marketing, newsletters, and automation.', - '_opentrust_sub_country' => 'LT', - '_opentrust_sub_website' => 'https://mailerlite.com', + '_ettic_otc_sub_purpose' => 'Email marketing, newsletters, and automation.', + '_ettic_otc_sub_country' => 'LT', + '_ettic_otc_sub_website' => 'https://mailerlite.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Subscriber email addresses, names, segmentation fields, and email engagement metrics.', + '_ettic_otc_sub_data_processed' => 'Subscriber email addresses, names, segmentation fields, and email engagement metrics.', ], ], @@ -1736,12 +1736,12 @@ 'name' => 'AWeber', 'aliases' => [ 'aweber' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Email marketing and autoresponder platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://aweber.com', + '_ettic_otc_sub_purpose' => 'Email marketing and autoresponder platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://aweber.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Subscriber email addresses, names, list membership, and campaign engagement data.', + '_ettic_otc_sub_data_processed' => 'Subscriber email addresses, names, list membership, and campaign engagement data.', ], ], @@ -1749,12 +1749,12 @@ 'name' => 'GetResponse', 'aliases' => [ 'getresponse', 'get response' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Email marketing, automation, and landing pages.', - '_opentrust_sub_country' => 'PL', - '_opentrust_sub_website' => 'https://getresponse.com', + '_ettic_otc_sub_purpose' => 'Email marketing, automation, and landing pages.', + '_ettic_otc_sub_country' => 'PL', + '_ettic_otc_sub_website' => 'https://getresponse.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Subscriber email addresses, names, segmentation data, and campaign engagement metrics.', + '_ettic_otc_sub_data_processed' => 'Subscriber email addresses, names, segmentation data, and campaign engagement metrics.', ], ], @@ -1762,12 +1762,12 @@ 'name' => 'Campaign Monitor', 'aliases' => [ 'campaignmonitor', 'campaign monitor' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Email marketing and transactional email delivery.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://campaignmonitor.com', + '_ettic_otc_sub_purpose' => 'Email marketing and transactional email delivery.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://campaignmonitor.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Subscriber email addresses, names, list data, and email engagement metrics.', + '_ettic_otc_sub_data_processed' => 'Subscriber email addresses, names, list data, and email engagement metrics.', ], ], @@ -1775,12 +1775,12 @@ 'name' => 'Drip', 'aliases' => [ 'drip', 'getdrip' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Email marketing and automation focused on ecommerce.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://drip.com', + '_ettic_otc_sub_purpose' => 'Email marketing and automation focused on ecommerce.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://drip.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Customer email addresses, purchase history, browsing events, and segmentation data.', + '_ettic_otc_sub_data_processed' => 'Customer email addresses, purchase history, browsing events, and segmentation data.', ], ], @@ -1788,12 +1788,12 @@ 'name' => 'Beehiiv', 'aliases' => [ 'beehiiv' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Newsletter publishing, audience growth, and monetization platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://beehiiv.com', + '_ettic_otc_sub_purpose' => 'Newsletter publishing, audience growth, and monetization platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://beehiiv.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Subscriber email addresses, names, engagement metrics, and referral data.', + '_ettic_otc_sub_data_processed' => 'Subscriber email addresses, names, engagement metrics, and referral data.', ], ], @@ -1801,12 +1801,12 @@ 'name' => 'EmailOctopus', 'aliases' => [ 'emailoctopus', 'email octopus' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Email marketing and newsletter delivery service.', - '_opentrust_sub_country' => 'GB', - '_opentrust_sub_website' => 'https://emailoctopus.com', + '_ettic_otc_sub_purpose' => 'Email marketing and newsletter delivery service.', + '_ettic_otc_sub_country' => 'GB', + '_ettic_otc_sub_website' => 'https://emailoctopus.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Subscriber email addresses, names, list membership, and campaign engagement metrics.', + '_ettic_otc_sub_data_processed' => 'Subscriber email addresses, names, list membership, and campaign engagement metrics.', ], ], @@ -1814,12 +1814,12 @@ 'name' => 'Close', 'aliases' => [ 'close', 'closecrm', 'close.io' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Sales CRM with built-in calling, email, and SMS.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://close.com', + '_ettic_otc_sub_purpose' => 'Sales CRM with built-in calling, email, and SMS.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://close.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Lead and contact details, call recordings, email threads, and sales pipeline data.', + '_ettic_otc_sub_data_processed' => 'Lead and contact details, call recordings, email threads, and sales pipeline data.', ], ], @@ -1827,12 +1827,12 @@ 'name' => 'Attio', 'aliases' => [ 'attio' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Customer relationship management and customer data platform.', - '_opentrust_sub_country' => 'GB', - '_opentrust_sub_website' => 'https://attio.com', + '_ettic_otc_sub_purpose' => 'Customer relationship management and customer data platform.', + '_ettic_otc_sub_country' => 'GB', + '_ettic_otc_sub_website' => 'https://attio.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Contact and company records, email metadata, and relationship activity history.', + '_ettic_otc_sub_data_processed' => 'Contact and company records, email metadata, and relationship activity history.', ], ], @@ -1840,12 +1840,12 @@ 'name' => 'Copper', 'aliases' => [ 'copper', 'coppercrm' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Customer relationship management integrated with Google Workspace.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://copper.com', + '_ettic_otc_sub_purpose' => 'Customer relationship management integrated with Google Workspace.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://copper.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Contact details, email threads, calendar events, and sales pipeline records.', + '_ettic_otc_sub_data_processed' => 'Contact details, email threads, calendar events, and sales pipeline records.', ], ], @@ -1855,12 +1855,12 @@ 'name' => 'Square', 'aliases' => [ 'square', 'squareup' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Payment processing, point of sale, and merchant services.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://squareup.com', + '_ettic_otc_sub_purpose' => 'Payment processing, point of sale, and merchant services.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://squareup.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Tokenized payment card details, customer names, billing information, and transaction records.', + '_ettic_otc_sub_data_processed' => 'Tokenized payment card details, customer names, billing information, and transaction records.', ], ], @@ -1868,12 +1868,12 @@ 'name' => 'Adyen', 'aliases' => [ 'adyen' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Global payment processing and unified commerce platform.', - '_opentrust_sub_country' => 'NL', - '_opentrust_sub_website' => 'https://adyen.com', + '_ettic_otc_sub_purpose' => 'Global payment processing and unified commerce platform.', + '_ettic_otc_sub_country' => 'NL', + '_ettic_otc_sub_website' => 'https://adyen.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Tokenized payment card details, billing addresses, customer identifiers, and transaction metadata.', + '_ettic_otc_sub_data_processed' => 'Tokenized payment card details, billing addresses, customer identifiers, and transaction metadata.', ], ], @@ -1881,12 +1881,12 @@ 'name' => 'Mollie', 'aliases' => [ 'mollie' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Payment processing for European businesses.', - '_opentrust_sub_country' => 'NL', - '_opentrust_sub_website' => 'https://mollie.com', + '_ettic_otc_sub_purpose' => 'Payment processing for European businesses.', + '_ettic_otc_sub_country' => 'NL', + '_ettic_otc_sub_website' => 'https://mollie.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Tokenized payment details, customer names, billing information, and transaction records.', + '_ettic_otc_sub_data_processed' => 'Tokenized payment details, customer names, billing information, and transaction records.', ], ], @@ -1894,12 +1894,12 @@ 'name' => 'GoCardless', 'aliases' => [ 'gocardless', 'go cardless' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Bank debit and recurring payment collection.', - '_opentrust_sub_country' => 'GB', - '_opentrust_sub_website' => 'https://gocardless.com', + '_ettic_otc_sub_purpose' => 'Bank debit and recurring payment collection.', + '_ettic_otc_sub_country' => 'GB', + '_ettic_otc_sub_website' => 'https://gocardless.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Bank account details, customer names, billing addresses, and mandate and transaction records.', + '_ettic_otc_sub_data_processed' => 'Bank account details, customer names, billing addresses, and mandate and transaction records.', ], ], @@ -1907,12 +1907,12 @@ 'name' => 'Checkout.com', 'aliases' => [ 'checkout', 'checkout.com' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Global online payment processing and acquiring.', - '_opentrust_sub_country' => 'GB', - '_opentrust_sub_website' => 'https://checkout.com', + '_ettic_otc_sub_purpose' => 'Global online payment processing and acquiring.', + '_ettic_otc_sub_country' => 'GB', + '_ettic_otc_sub_website' => 'https://checkout.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Tokenized payment card details, billing addresses, customer identifiers, and transaction metadata.', + '_ettic_otc_sub_data_processed' => 'Tokenized payment card details, billing addresses, customer identifiers, and transaction metadata.', ], ], @@ -1920,12 +1920,12 @@ 'name' => 'Wise Business', 'aliases' => [ 'wise', 'transferwise', 'wise business' ], 'fields' => [ - '_opentrust_sub_purpose' => 'International business payments, multi-currency accounts, and FX.', - '_opentrust_sub_country' => 'GB', - '_opentrust_sub_website' => 'https://wise.com/business', + '_ettic_otc_sub_purpose' => 'International business payments, multi-currency accounts, and FX.', + '_ettic_otc_sub_country' => 'GB', + '_ettic_otc_sub_website' => 'https://wise.com/business', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Business and beneficiary bank details, payer and payee names, and transaction records.', + '_ettic_otc_sub_data_processed' => 'Business and beneficiary bank details, payer and payee names, and transaction records.', ], ], @@ -1935,12 +1935,12 @@ 'name' => 'Okta', 'aliases' => [ 'okta' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Workforce and customer identity, single sign-on, and access management.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://okta.com', + '_ettic_otc_sub_purpose' => 'Workforce and customer identity, single sign-on, and access management.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://okta.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User directory attributes, authentication events, group memberships, and session metadata.', + '_ettic_otc_sub_data_processed' => 'User directory attributes, authentication events, group memberships, and session metadata.', ], ], @@ -1948,12 +1948,12 @@ 'name' => 'OneLogin', 'aliases' => [ 'onelogin', 'one login' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Identity and access management with single sign-on and MFA.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://onelogin.com', + '_ettic_otc_sub_purpose' => 'Identity and access management with single sign-on and MFA.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://onelogin.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User directory attributes, authentication events, and session and device metadata.', + '_ettic_otc_sub_data_processed' => 'User directory attributes, authentication events, and session and device metadata.', ], ], @@ -1961,12 +1961,12 @@ 'name' => 'Duo Security', 'aliases' => [ 'duo', 'duo security', 'cisco duo' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Multi-factor authentication and device trust.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://duo.com', + '_ettic_otc_sub_purpose' => 'Multi-factor authentication and device trust.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://duo.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User identifiers, device fingerprints, authentication events, and phone numbers for MFA.', + '_ettic_otc_sub_data_processed' => 'User identifiers, device fingerprints, authentication events, and phone numbers for MFA.', ], ], @@ -1974,12 +1974,12 @@ 'name' => 'Kinde', 'aliases' => [ 'kinde' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Customer authentication, user management, and feature flags for applications.', - '_opentrust_sub_country' => 'AU', - '_opentrust_sub_website' => 'https://kinde.com', + '_ettic_otc_sub_purpose' => 'Customer authentication, user management, and feature flags for applications.', + '_ettic_otc_sub_country' => 'AU', + '_ettic_otc_sub_website' => 'https://kinde.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'End user email addresses, names, authentication events, and profile attributes.', + '_ettic_otc_sub_data_processed' => 'End user email addresses, names, authentication events, and profile attributes.', ], ], @@ -1987,12 +1987,12 @@ 'name' => 'SuperTokens', 'aliases' => [ 'supertokens', 'super tokens' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Open-source authentication platform with managed and self-hosted options.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://supertokens.com', + '_ettic_otc_sub_purpose' => 'Open-source authentication platform with managed and self-hosted options.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://supertokens.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'End user email addresses, hashed credentials, session tokens, and profile attributes.', + '_ettic_otc_sub_data_processed' => 'End user email addresses, hashed credentials, session tokens, and profile attributes.', ], ], @@ -2000,12 +2000,12 @@ 'name' => '1Password Business', 'aliases' => [ '1password', 'onepassword', '1pw' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Password and secrets management for teams.', - '_opentrust_sub_country' => 'CA', - '_opentrust_sub_website' => 'https://1password.com/business', + '_ettic_otc_sub_purpose' => 'Password and secrets management for teams.', + '_ettic_otc_sub_country' => 'CA', + '_ettic_otc_sub_website' => 'https://1password.com/business', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Encrypted vault contents, user account details, and access and audit logs.', + '_ettic_otc_sub_data_processed' => 'Encrypted vault contents, user account details, and access and audit logs.', ], ], @@ -2013,12 +2013,12 @@ 'name' => 'Bitwarden Business', 'aliases' => [ 'bitwarden' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Open-source password and secrets management for teams.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://bitwarden.com/products/business', + '_ettic_otc_sub_purpose' => 'Open-source password and secrets management for teams.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://bitwarden.com/products/business', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Encrypted vault contents, user account details, and access and audit logs.', + '_ettic_otc_sub_data_processed' => 'Encrypted vault contents, user account details, and access and audit logs.', ], ], @@ -2028,11 +2028,11 @@ 'name' => 'Elastic Cloud', 'aliases' => [ 'elastic', 'elasticsearch', 'elastic cloud' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed Elasticsearch, search, and observability service.', - '_opentrust_sub_website' => 'https://elastic.co/cloud', + '_ettic_otc_sub_purpose' => 'Managed Elasticsearch, search, and observability service.', + '_ettic_otc_sub_website' => 'https://elastic.co/cloud', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Indexed documents, search queries, and any identifiers contained in ingested data.', + '_ettic_otc_sub_data_processed' => 'Indexed documents, search queries, and any identifiers contained in ingested data.', ], ], @@ -2040,11 +2040,11 @@ 'name' => 'Redis Cloud', 'aliases' => [ 'redis', 'redis cloud', 'redis enterprise' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed Redis database and in-memory data platform.', - '_opentrust_sub_website' => 'https://redis.io/cloud', + '_ettic_otc_sub_purpose' => 'Managed Redis database and in-memory data platform.', + '_ettic_otc_sub_website' => 'https://redis.io/cloud', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Cached and stored key-value data, including any identifiers written by the application.', + '_ettic_otc_sub_data_processed' => 'Cached and stored key-value data, including any identifiers written by the application.', ], ], @@ -2052,11 +2052,11 @@ 'name' => 'CockroachDB Cloud', 'aliases' => [ 'cockroach', 'cockroachdb', 'cockroach cloud' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed distributed SQL database service.', - '_opentrust_sub_website' => 'https://cockroachlabs.com/product/cockroachdb-cloud', + '_ettic_otc_sub_purpose' => 'Managed distributed SQL database service.', + '_ettic_otc_sub_website' => 'https://cockroachlabs.com/product/cockroachdb-cloud', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application database contents, including any personal data written by the application.', + '_ettic_otc_sub_data_processed' => 'Application database contents, including any personal data written by the application.', ], ], @@ -2064,11 +2064,11 @@ 'name' => 'Fauna', 'aliases' => [ 'fauna', 'faunadb' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Serverless distributed document and relational database.', - '_opentrust_sub_website' => 'https://fauna.com', + '_ettic_otc_sub_purpose' => 'Serverless distributed document and relational database.', + '_ettic_otc_sub_website' => 'https://fauna.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application database contents, including any personal data written by the application.', + '_ettic_otc_sub_data_processed' => 'Application database contents, including any personal data written by the application.', ], ], @@ -2076,11 +2076,11 @@ 'name' => 'Xata', 'aliases' => [ 'xata' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Serverless database platform with built-in search and analytics.', - '_opentrust_sub_website' => 'https://xata.io', + '_ettic_otc_sub_purpose' => 'Serverless database platform with built-in search and analytics.', + '_ettic_otc_sub_website' => 'https://xata.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Application database contents, including any personal data written by the application.', + '_ettic_otc_sub_data_processed' => 'Application database contents, including any personal data written by the application.', ], ], @@ -2090,12 +2090,12 @@ 'name' => 'Cohere', 'aliases' => [ 'cohere' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Large language model APIs for text generation, embeddings, and retrieval.', - '_opentrust_sub_country' => 'CA', - '_opentrust_sub_website' => 'https://cohere.com', + '_ettic_otc_sub_purpose' => 'Large language model APIs for text generation, embeddings, and retrieval.', + '_ettic_otc_sub_country' => 'CA', + '_ettic_otc_sub_website' => 'https://cohere.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Prompt and completion text, embeddings input, and API usage metadata.', + '_ettic_otc_sub_data_processed' => 'Prompt and completion text, embeddings input, and API usage metadata.', ], ], @@ -2103,12 +2103,12 @@ 'name' => 'Hugging Face', 'aliases' => [ 'huggingface', 'hugging face', 'hf' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Machine learning model hosting, inference APIs, and collaboration platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://huggingface.co', + '_ettic_otc_sub_purpose' => 'Machine learning model hosting, inference APIs, and collaboration platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://huggingface.co', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Model inference inputs and outputs, uploaded datasets, and account metadata.', + '_ettic_otc_sub_data_processed' => 'Model inference inputs and outputs, uploaded datasets, and account metadata.', ], ], @@ -2116,12 +2116,12 @@ 'name' => 'Groq', 'aliases' => [ 'groq' ], 'fields' => [ - '_opentrust_sub_purpose' => 'High-speed inference API for large language models.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://groq.com', + '_ettic_otc_sub_purpose' => 'High-speed inference API for large language models.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://groq.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Prompt and completion text and API usage metadata.', + '_ettic_otc_sub_data_processed' => 'Prompt and completion text and API usage metadata.', ], ], @@ -2129,12 +2129,12 @@ 'name' => 'Together AI', 'aliases' => [ 'together', 'together ai', 'togetherai' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Inference and fine-tuning APIs for open-source large language models.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://together.ai', + '_ettic_otc_sub_purpose' => 'Inference and fine-tuning APIs for open-source large language models.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://together.ai', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Prompt and completion text, fine-tuning datasets, and API usage metadata.', + '_ettic_otc_sub_data_processed' => 'Prompt and completion text, fine-tuning datasets, and API usage metadata.', ], ], @@ -2142,12 +2142,12 @@ 'name' => 'Fireworks AI', 'aliases' => [ 'fireworks', 'fireworks ai' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Inference platform for open-source generative AI models.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://fireworks.ai', + '_ettic_otc_sub_purpose' => 'Inference platform for open-source generative AI models.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://fireworks.ai', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Prompt and completion text, fine-tuning datasets, and API usage metadata.', + '_ettic_otc_sub_data_processed' => 'Prompt and completion text, fine-tuning datasets, and API usage metadata.', ], ], @@ -2155,12 +2155,12 @@ 'name' => 'ElevenLabs', 'aliases' => [ 'elevenlabs', 'eleven labs', '11labs' ], 'fields' => [ - '_opentrust_sub_purpose' => 'AI voice synthesis, text to speech, and voice cloning APIs.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://elevenlabs.io', + '_ettic_otc_sub_purpose' => 'AI voice synthesis, text to speech, and voice cloning APIs.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://elevenlabs.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Submitted text, voice samples, generated audio, and API usage metadata.', + '_ettic_otc_sub_data_processed' => 'Submitted text, voice samples, generated audio, and API usage metadata.', ], ], @@ -2168,12 +2168,12 @@ 'name' => 'AssemblyAI', 'aliases' => [ 'assemblyai', 'assembly ai' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Speech to text, transcription, and audio intelligence APIs.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://assemblyai.com', + '_ettic_otc_sub_purpose' => 'Speech to text, transcription, and audio intelligence APIs.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://assemblyai.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Uploaded audio recordings, generated transcripts, and API usage metadata.', + '_ettic_otc_sub_data_processed' => 'Uploaded audio recordings, generated transcripts, and API usage metadata.', ], ], @@ -2181,12 +2181,12 @@ 'name' => 'Deepgram', 'aliases' => [ 'deepgram' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Speech to text and voice AI APIs for real-time and batch transcription.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://deepgram.com', + '_ettic_otc_sub_purpose' => 'Speech to text and voice AI APIs for real-time and batch transcription.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://deepgram.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Uploaded audio, streamed voice data, generated transcripts, and API usage metadata.', + '_ettic_otc_sub_data_processed' => 'Uploaded audio, streamed voice data, generated transcripts, and API usage metadata.', ], ], @@ -2194,12 +2194,12 @@ 'name' => 'Pinecone', 'aliases' => [ 'pinecone' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed vector database for similarity search and retrieval augmented generation.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://pinecone.io', + '_ettic_otc_sub_purpose' => 'Managed vector database for similarity search and retrieval augmented generation.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://pinecone.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Stored vector embeddings, associated metadata, and query inputs.', + '_ettic_otc_sub_data_processed' => 'Stored vector embeddings, associated metadata, and query inputs.', ], ], @@ -2207,11 +2207,11 @@ 'name' => 'Weaviate', 'aliases' => [ 'weaviate' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed vector database and AI-native search engine.', - '_opentrust_sub_website' => 'https://weaviate.io', + '_ettic_otc_sub_purpose' => 'Managed vector database and AI-native search engine.', + '_ettic_otc_sub_website' => 'https://weaviate.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Stored vector embeddings, associated metadata, and query inputs.', + '_ettic_otc_sub_data_processed' => 'Stored vector embeddings, associated metadata, and query inputs.', ], ], @@ -2219,11 +2219,11 @@ 'name' => 'Qdrant', 'aliases' => [ 'qdrant' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed vector database for semantic search and AI applications.', - '_opentrust_sub_website' => 'https://qdrant.tech', + '_ettic_otc_sub_purpose' => 'Managed vector database for semantic search and AI applications.', + '_ettic_otc_sub_website' => 'https://qdrant.tech', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Stored vector embeddings, associated metadata, and query inputs.', + '_ettic_otc_sub_data_processed' => 'Stored vector embeddings, associated metadata, and query inputs.', ], ], @@ -2233,12 +2233,12 @@ 'name' => 'Mux', 'aliases' => [ 'mux' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Video streaming infrastructure, encoding, and playback analytics.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://mux.com', + '_ettic_otc_sub_purpose' => 'Video streaming infrastructure, encoding, and playback analytics.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://mux.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Uploaded video assets, viewer IP addresses, playback events, and device metadata.', + '_ettic_otc_sub_data_processed' => 'Uploaded video assets, viewer IP addresses, playback events, and device metadata.', ], ], @@ -2246,12 +2246,12 @@ 'name' => 'Vimeo', 'aliases' => [ 'vimeo' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Video hosting, streaming, and player services.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://vimeo.com', + '_ettic_otc_sub_purpose' => 'Video hosting, streaming, and player services.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://vimeo.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Uploaded video assets, viewer IP addresses, playback events, and account information.', + '_ettic_otc_sub_data_processed' => 'Uploaded video assets, viewer IP addresses, playback events, and account information.', ], ], @@ -2259,12 +2259,12 @@ 'name' => 'Wistia', 'aliases' => [ 'wistia' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Business video hosting, player, and engagement analytics.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://wistia.com', + '_ettic_otc_sub_purpose' => 'Business video hosting, player, and engagement analytics.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://wistia.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Uploaded video assets, viewer IP addresses, engagement events, and lead capture data.', + '_ettic_otc_sub_data_processed' => 'Uploaded video assets, viewer IP addresses, engagement events, and lead capture data.', ], ], @@ -2272,12 +2272,12 @@ 'name' => 'Daily.co', 'aliases' => [ 'daily', 'daily.co' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Real-time video and audio APIs for embedded calls and meetings.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://daily.co', + '_ettic_otc_sub_purpose' => 'Real-time video and audio APIs for embedded calls and meetings.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://daily.co', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Participant audio and video streams, session metadata, and optional recordings.', + '_ettic_otc_sub_data_processed' => 'Participant audio and video streams, session metadata, and optional recordings.', ], ], @@ -2285,12 +2285,12 @@ 'name' => 'LiveKit', 'aliases' => [ 'livekit', 'live kit' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Real-time audio, video, and data infrastructure built on WebRTC.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://livekit.io', + '_ettic_otc_sub_purpose' => 'Real-time audio, video, and data infrastructure built on WebRTC.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://livekit.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Participant audio and video streams, session metadata, and optional recordings.', + '_ettic_otc_sub_data_processed' => 'Participant audio and video streams, session metadata, and optional recordings.', ], ], @@ -2298,11 +2298,11 @@ 'name' => 'Agora', 'aliases' => [ 'agora', 'agora.io' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Real-time voice, video, and interactive streaming APIs.', - '_opentrust_sub_website' => 'https://agora.io', + '_ettic_otc_sub_purpose' => 'Real-time voice, video, and interactive streaming APIs.', + '_ettic_otc_sub_website' => 'https://agora.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Participant audio and video streams, session metadata, and optional recordings.', + '_ettic_otc_sub_data_processed' => 'Participant audio and video streams, session metadata, and optional recordings.', ], ], @@ -2312,12 +2312,12 @@ 'name' => 'Jira', 'aliases' => [ 'jira', 'atlassian jira' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Issue tracking and agile project management.', - '_opentrust_sub_country' => 'AU', - '_opentrust_sub_website' => 'https://atlassian.com/software/jira', + '_ettic_otc_sub_purpose' => 'Issue tracking and agile project management.', + '_ettic_otc_sub_country' => 'AU', + '_ettic_otc_sub_website' => 'https://atlassian.com/software/jira', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User account details, issue contents, comments, attachments, and project metadata.', + '_ettic_otc_sub_data_processed' => 'User account details, issue contents, comments, attachments, and project metadata.', ], ], @@ -2325,12 +2325,12 @@ 'name' => 'Confluence', 'aliases' => [ 'confluence', 'atlassian confluence' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Team wiki and documentation collaboration.', - '_opentrust_sub_country' => 'AU', - '_opentrust_sub_website' => 'https://atlassian.com/software/confluence', + '_ettic_otc_sub_purpose' => 'Team wiki and documentation collaboration.', + '_ettic_otc_sub_country' => 'AU', + '_ettic_otc_sub_website' => 'https://atlassian.com/software/confluence', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User account details, page contents, comments, attachments, and space metadata.', + '_ettic_otc_sub_data_processed' => 'User account details, page contents, comments, attachments, and space metadata.', ], ], @@ -2338,12 +2338,12 @@ 'name' => 'ClickUp', 'aliases' => [ 'clickup', 'click up' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Project management, task tracking, and team collaboration.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://clickup.com', + '_ettic_otc_sub_purpose' => 'Project management, task tracking, and team collaboration.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://clickup.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User account details, task contents, comments, attachments, and workspace metadata.', + '_ettic_otc_sub_data_processed' => 'User account details, task contents, comments, attachments, and workspace metadata.', ], ], @@ -2351,12 +2351,12 @@ 'name' => 'Monday.com', 'aliases' => [ 'monday', 'monday.com' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Work management and team collaboration platform.', - '_opentrust_sub_country' => 'IL', - '_opentrust_sub_website' => 'https://monday.com', + '_ettic_otc_sub_purpose' => 'Work management and team collaboration platform.', + '_ettic_otc_sub_country' => 'IL', + '_ettic_otc_sub_website' => 'https://monday.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User account details, board and item contents, comments, and attachments.', + '_ettic_otc_sub_data_processed' => 'User account details, board and item contents, comments, and attachments.', ], ], @@ -2364,12 +2364,12 @@ 'name' => 'Airtable', 'aliases' => [ 'airtable' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Cloud database and spreadsheet collaboration platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://airtable.com', + '_ettic_otc_sub_purpose' => 'Cloud database and spreadsheet collaboration platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://airtable.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User account details, base records, attachments, and workspace metadata.', + '_ettic_otc_sub_data_processed' => 'User account details, base records, attachments, and workspace metadata.', ], ], @@ -2377,12 +2377,12 @@ 'name' => 'Coda', 'aliases' => [ 'coda', 'coda.io' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Collaborative documents combining text, tables, and automations.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://coda.io', + '_ettic_otc_sub_purpose' => 'Collaborative documents combining text, tables, and automations.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://coda.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User account details, document contents, comments, and attachments.', + '_ettic_otc_sub_data_processed' => 'User account details, document contents, comments, and attachments.', ], ], @@ -2390,11 +2390,11 @@ 'name' => 'Miro', 'aliases' => [ 'miro', 'realtimeboard' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Online collaborative whiteboard and visual workspace.', - '_opentrust_sub_website' => 'https://miro.com', + '_ettic_otc_sub_purpose' => 'Online collaborative whiteboard and visual workspace.', + '_ettic_otc_sub_website' => 'https://miro.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User account details, board contents, comments, and attachments.', + '_ettic_otc_sub_data_processed' => 'User account details, board contents, comments, and attachments.', ], ], @@ -2402,12 +2402,12 @@ 'name' => 'Loom', 'aliases' => [ 'loom', 'useloom' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Asynchronous video messaging and screen recording.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://loom.com', + '_ettic_otc_sub_purpose' => 'Asynchronous video messaging and screen recording.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://loom.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Recorded video and audio, viewer identifiers, engagement events, and account details.', + '_ettic_otc_sub_data_processed' => 'Recorded video and audio, viewer identifiers, engagement events, and account details.', ], ], @@ -2415,12 +2415,12 @@ 'name' => 'Microsoft Teams', 'aliases' => [ 'teams', 'msteams', 'ms teams' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Team chat, meetings, and collaboration within Microsoft 365.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://microsoft.com/microsoft-teams', + '_ettic_otc_sub_purpose' => 'Team chat, meetings, and collaboration within Microsoft 365.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://microsoft.com/microsoft-teams', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User account details, chat messages, meeting recordings, files, and presence information.', + '_ettic_otc_sub_data_processed' => 'User account details, chat messages, meeting recordings, files, and presence information.', ], ], @@ -2430,12 +2430,12 @@ 'name' => 'Gusto', 'aliases' => [ 'gusto' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Payroll, benefits, and HR administration for US employers.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://gusto.com', + '_ettic_otc_sub_purpose' => 'Payroll, benefits, and HR administration for US employers.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://gusto.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Employee names, Social Security numbers, bank details, compensation, and tax information.', + '_ettic_otc_sub_data_processed' => 'Employee names, Social Security numbers, bank details, compensation, and tax information.', ], ], @@ -2443,12 +2443,12 @@ 'name' => 'Deel', 'aliases' => [ 'deel' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Global payroll, contractor management, and employer of record services.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://deel.com', + '_ettic_otc_sub_purpose' => 'Global payroll, contractor management, and employer of record services.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://deel.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Worker names, tax identifiers, bank details, contracts, and compensation records.', + '_ettic_otc_sub_data_processed' => 'Worker names, tax identifiers, bank details, contracts, and compensation records.', ], ], @@ -2456,12 +2456,12 @@ 'name' => 'Remote', 'aliases' => [ 'remote', 'remote.com' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Global employer of record, payroll, and contractor management.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://remote.com', + '_ettic_otc_sub_purpose' => 'Global employer of record, payroll, and contractor management.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://remote.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Worker names, tax identifiers, bank details, contracts, and compensation records.', + '_ettic_otc_sub_data_processed' => 'Worker names, tax identifiers, bank details, contracts, and compensation records.', ], ], @@ -2469,12 +2469,12 @@ 'name' => 'Rippling', 'aliases' => [ 'rippling' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Unified HR, payroll, IT, and finance platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://rippling.com', + '_ettic_otc_sub_purpose' => 'Unified HR, payroll, IT, and finance platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://rippling.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Employee personal details, tax identifiers, bank information, device data, and app access logs.', + '_ettic_otc_sub_data_processed' => 'Employee personal details, tax identifiers, bank information, device data, and app access logs.', ], ], @@ -2482,12 +2482,12 @@ 'name' => 'BambooHR', 'aliases' => [ 'bamboohr', 'bamboo hr' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Human resources information system for small and medium businesses.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://bamboohr.com', + '_ettic_otc_sub_purpose' => 'Human resources information system for small and medium businesses.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://bamboohr.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Employee personal details, employment history, compensation, and performance records.', + '_ettic_otc_sub_data_processed' => 'Employee personal details, employment history, compensation, and performance records.', ], ], @@ -2495,12 +2495,12 @@ 'name' => 'Personio', 'aliases' => [ 'personio' ], 'fields' => [ - '_opentrust_sub_purpose' => 'HR management, recruiting, and payroll for European businesses.', - '_opentrust_sub_country' => 'DE', - '_opentrust_sub_website' => 'https://personio.com', + '_ettic_otc_sub_purpose' => 'HR management, recruiting, and payroll for European businesses.', + '_ettic_otc_sub_country' => 'DE', + '_ettic_otc_sub_website' => 'https://personio.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Employee personal details, employment records, compensation, and applicant data.', + '_ettic_otc_sub_data_processed' => 'Employee personal details, employment records, compensation, and applicant data.', ], ], @@ -2510,12 +2510,12 @@ 'name' => 'DocuSign', 'aliases' => [ 'docusign', 'docu sign' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Electronic signature and agreement management.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://docusign.com', + '_ettic_otc_sub_purpose' => 'Electronic signature and agreement management.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://docusign.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Signer names, email addresses, IP addresses, signed documents, and audit trails.', + '_ettic_otc_sub_data_processed' => 'Signer names, email addresses, IP addresses, signed documents, and audit trails.', ], ], @@ -2523,12 +2523,12 @@ 'name' => 'Dropbox Sign', 'aliases' => [ 'dropbox sign', 'hellosign' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Electronic signature service, formerly HelloSign.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://dropbox.com/sign', + '_ettic_otc_sub_purpose' => 'Electronic signature service, formerly HelloSign.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://dropbox.com/sign', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Signer names, email addresses, IP addresses, signed documents, and audit trails.', + '_ettic_otc_sub_data_processed' => 'Signer names, email addresses, IP addresses, signed documents, and audit trails.', ], ], @@ -2536,12 +2536,12 @@ 'name' => 'PandaDoc', 'aliases' => [ 'pandadoc', 'panda doc' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Document automation, proposals, and electronic signature.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://pandadoc.com', + '_ettic_otc_sub_purpose' => 'Document automation, proposals, and electronic signature.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://pandadoc.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Signer names, email addresses, IP addresses, document contents, and audit trails.', + '_ettic_otc_sub_data_processed' => 'Signer names, email addresses, IP addresses, document contents, and audit trails.', ], ], @@ -2551,12 +2551,12 @@ 'name' => 'LaunchDarkly', 'aliases' => [ 'launchdarkly', 'launch darkly' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Feature flag management and progressive delivery platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://launchdarkly.com', + '_ettic_otc_sub_purpose' => 'Feature flag management and progressive delivery platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://launchdarkly.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'End user identifiers, targeting attributes, and feature evaluation events.', + '_ettic_otc_sub_data_processed' => 'End user identifiers, targeting attributes, and feature evaluation events.', ], ], @@ -2564,12 +2564,12 @@ 'name' => 'Statsig', 'aliases' => [ 'statsig' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Feature flags, experimentation, and product analytics.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://statsig.com', + '_ettic_otc_sub_purpose' => 'Feature flags, experimentation, and product analytics.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://statsig.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'End user identifiers, targeting attributes, and product event data.', + '_ettic_otc_sub_data_processed' => 'End user identifiers, targeting attributes, and product event data.', ], ], @@ -2577,12 +2577,12 @@ 'name' => 'GrowthBook', 'aliases' => [ 'growthbook', 'growth book' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Open-source feature flags and A/B testing platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://growthbook.io', + '_ettic_otc_sub_purpose' => 'Open-source feature flags and A/B testing platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://growthbook.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'End user identifiers, targeting attributes, and experiment event data.', + '_ettic_otc_sub_data_processed' => 'End user identifiers, targeting attributes, and experiment event data.', ], ], @@ -2590,12 +2590,12 @@ 'name' => 'Split', 'aliases' => [ 'split', 'split.io' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Feature delivery and experimentation platform.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://split.io', + '_ettic_otc_sub_purpose' => 'Feature delivery and experimentation platform.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://split.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'End user identifiers, targeting attributes, and feature evaluation events.', + '_ettic_otc_sub_data_processed' => 'End user identifiers, targeting attributes, and feature evaluation events.', ], ], @@ -2603,12 +2603,12 @@ 'name' => 'ConfigCat', 'aliases' => [ 'configcat', 'config cat' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Feature flag and configuration management service.', - '_opentrust_sub_country' => 'HU', - '_opentrust_sub_website' => 'https://configcat.com', + '_ettic_otc_sub_purpose' => 'Feature flag and configuration management service.', + '_ettic_otc_sub_country' => 'HU', + '_ettic_otc_sub_website' => 'https://configcat.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'End user identifiers, targeting attributes, and feature evaluation events.', + '_ettic_otc_sub_data_processed' => 'End user identifiers, targeting attributes, and feature evaluation events.', ], ], @@ -2618,12 +2618,12 @@ 'name' => 'Inngest', 'aliases' => [ 'inngest' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Durable workflow and background job orchestration for developers.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://inngest.com', + '_ettic_otc_sub_purpose' => 'Durable workflow and background job orchestration for developers.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://inngest.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Event payloads, function inputs and outputs, and execution logs.', + '_ettic_otc_sub_data_processed' => 'Event payloads, function inputs and outputs, and execution logs.', ], ], @@ -2631,12 +2631,12 @@ 'name' => 'Trigger.dev', 'aliases' => [ 'trigger', 'trigger.dev' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Background jobs and workflow orchestration platform for developers.', - '_opentrust_sub_country' => 'GB', - '_opentrust_sub_website' => 'https://trigger.dev', + '_ettic_otc_sub_purpose' => 'Background jobs and workflow orchestration platform for developers.', + '_ettic_otc_sub_country' => 'GB', + '_ettic_otc_sub_website' => 'https://trigger.dev', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Event payloads, job inputs and outputs, and execution logs.', + '_ettic_otc_sub_data_processed' => 'Event payloads, job inputs and outputs, and execution logs.', ], ], @@ -2644,12 +2644,12 @@ 'name' => 'Temporal Cloud', 'aliases' => [ 'temporal', 'temporal cloud', 'temporal.io' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed durable execution and workflow orchestration service.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://temporal.io/cloud', + '_ettic_otc_sub_purpose' => 'Managed durable execution and workflow orchestration service.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://temporal.io/cloud', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Workflow inputs and outputs, activity payloads, and execution history.', + '_ettic_otc_sub_data_processed' => 'Workflow inputs and outputs, activity payloads, and execution history.', ], ], @@ -2657,12 +2657,12 @@ 'name' => 'Hatchet', 'aliases' => [ 'hatchet' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Distributed task queue and background job orchestration.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://hatchet.run', + '_ettic_otc_sub_purpose' => 'Distributed task queue and background job orchestration.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://hatchet.run', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Task payloads, job inputs and outputs, and execution logs.', + '_ettic_otc_sub_data_processed' => 'Task payloads, job inputs and outputs, and execution logs.', ], ], @@ -2672,12 +2672,12 @@ 'name' => 'Zapier', 'aliases' => [ 'zapier' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Automation platform connecting SaaS apps with triggers and actions.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://zapier.com', + '_ettic_otc_sub_purpose' => 'Automation platform connecting SaaS apps with triggers and actions.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://zapier.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Data passed between connected applications, including any personal data in workflow payloads.', + '_ettic_otc_sub_data_processed' => 'Data passed between connected applications, including any personal data in workflow payloads.', ], ], @@ -2685,12 +2685,12 @@ 'name' => 'Make', 'aliases' => [ 'make', 'integromat' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Visual automation and integration platform, formerly Integromat.', - '_opentrust_sub_country' => 'CZ', - '_opentrust_sub_website' => 'https://make.com', + '_ettic_otc_sub_purpose' => 'Visual automation and integration platform, formerly Integromat.', + '_ettic_otc_sub_country' => 'CZ', + '_ettic_otc_sub_website' => 'https://make.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Data passed between connected applications, including any personal data in scenario payloads.', + '_ettic_otc_sub_data_processed' => 'Data passed between connected applications, including any personal data in scenario payloads.', ], ], @@ -2698,12 +2698,12 @@ 'name' => 'n8n Cloud', 'aliases' => [ 'n8n', 'n8n cloud' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed workflow automation platform based on n8n.', - '_opentrust_sub_country' => 'DE', - '_opentrust_sub_website' => 'https://n8n.io/cloud', + '_ettic_otc_sub_purpose' => 'Managed workflow automation platform based on n8n.', + '_ettic_otc_sub_country' => 'DE', + '_ettic_otc_sub_website' => 'https://n8n.io/cloud', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Data passed between connected applications, including any personal data in workflow payloads.', + '_ettic_otc_sub_data_processed' => 'Data passed between connected applications, including any personal data in workflow payloads.', ], ], @@ -2711,12 +2711,12 @@ 'name' => 'Pipedream', 'aliases' => [ 'pipedream' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Integration and workflow automation platform for developers.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://pipedream.com', + '_ettic_otc_sub_purpose' => 'Integration and workflow automation platform for developers.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://pipedream.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Event payloads, workflow inputs and outputs, and execution logs.', + '_ettic_otc_sub_data_processed' => 'Event payloads, workflow inputs and outputs, and execution logs.', ], ], @@ -2724,12 +2724,12 @@ 'name' => 'Retool', 'aliases' => [ 'retool' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Low-code platform for building internal tools and applications.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://retool.com', + '_ettic_otc_sub_purpose' => 'Low-code platform for building internal tools and applications.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://retool.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'User account details, query results from connected data sources, and audit logs.', + '_ettic_otc_sub_data_processed' => 'User account details, query results from connected data sources, and audit logs.', ], ], @@ -2739,12 +2739,12 @@ 'name' => 'Webflow', 'aliases' => [ 'webflow' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Visual website builder, CMS, and hosting.', - '_opentrust_sub_country' => 'US', - '_opentrust_sub_website' => 'https://webflow.com', + '_ettic_otc_sub_purpose' => 'Visual website builder, CMS, and hosting.', + '_ettic_otc_sub_country' => 'US', + '_ettic_otc_sub_website' => 'https://webflow.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Website content, form submissions, visitor analytics, and customer account details.', + '_ettic_otc_sub_data_processed' => 'Website content, form submissions, visitor analytics, and customer account details.', ], ], @@ -2752,12 +2752,12 @@ 'name' => 'Framer', 'aliases' => [ 'framer' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Website builder and design tool with hosting.', - '_opentrust_sub_country' => 'NL', - '_opentrust_sub_website' => 'https://framer.com', + '_ettic_otc_sub_purpose' => 'Website builder and design tool with hosting.', + '_ettic_otc_sub_country' => 'NL', + '_ettic_otc_sub_website' => 'https://framer.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Website content, form submissions, visitor analytics, and customer account details.', + '_ettic_otc_sub_data_processed' => 'Website content, form submissions, visitor analytics, and customer account details.', ], ], @@ -2765,12 +2765,12 @@ 'name' => 'Shopify', 'aliases' => [ 'shopify' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Ecommerce platform for online stores and retail point of sale.', - '_opentrust_sub_country' => 'CA', - '_opentrust_sub_website' => 'https://shopify.com', + '_ettic_otc_sub_purpose' => 'Ecommerce platform for online stores and retail point of sale.', + '_ettic_otc_sub_country' => 'CA', + '_ettic_otc_sub_website' => 'https://shopify.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Customer names, email addresses, shipping addresses, order history, and payment metadata.', + '_ettic_otc_sub_data_processed' => 'Customer names, email addresses, shipping addresses, order history, and payment metadata.', ], ], @@ -2778,12 +2778,12 @@ 'name' => 'Contentful', 'aliases' => [ 'contentful' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Headless content management system and content delivery APIs.', - '_opentrust_sub_country' => 'DE', - '_opentrust_sub_website' => 'https://contentful.com', + '_ettic_otc_sub_purpose' => 'Headless content management system and content delivery APIs.', + '_ettic_otc_sub_country' => 'DE', + '_ettic_otc_sub_website' => 'https://contentful.com', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Content entries, media assets, and editor account details.', + '_ettic_otc_sub_data_processed' => 'Content entries, media assets, and editor account details.', ], ], @@ -2791,12 +2791,12 @@ 'name' => 'Sanity', 'aliases' => [ 'sanity', 'sanity.io' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Headless content platform with structured content and real-time APIs.', - '_opentrust_sub_country' => 'NO', - '_opentrust_sub_website' => 'https://sanity.io', + '_ettic_otc_sub_purpose' => 'Headless content platform with structured content and real-time APIs.', + '_ettic_otc_sub_country' => 'NO', + '_ettic_otc_sub_website' => 'https://sanity.io', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Content documents, media assets, and editor account details.', + '_ettic_otc_sub_data_processed' => 'Content documents, media assets, and editor account details.', ], ], @@ -2804,12 +2804,12 @@ 'name' => 'Strapi Cloud', 'aliases' => [ 'strapi', 'strapi cloud' ], 'fields' => [ - '_opentrust_sub_purpose' => 'Managed hosting for the Strapi headless CMS.', - '_opentrust_sub_country' => 'FR', - '_opentrust_sub_website' => 'https://strapi.io/cloud', + '_ettic_otc_sub_purpose' => 'Managed hosting for the Strapi headless CMS.', + '_ettic_otc_sub_country' => 'FR', + '_ettic_otc_sub_website' => 'https://strapi.io/cloud', ], 'fields_review' => [ - '_opentrust_sub_data_processed' => 'Content entries, media assets, and editor account details.', + '_ettic_otc_sub_data_processed' => 'Content entries, media assets, and editor account details.', ], ], diff --git a/open-trust-center-by-ettic.php b/open-trust-center-by-ettic.php index 790b733..a730e16 100644 --- a/open-trust-center-by-ettic.php +++ b/open-trust-center-by-ettic.php @@ -63,8 +63,8 @@ // First-install defaults. Autoload=no — the option is a sizeable array // carrying encrypted Turnstile secret + per-site salt, and we'd rather // not load it on every front-end request that never touches Ettic_OTC. - if (false === get_option('opentrust_settings')) { - add_option('opentrust_settings', Ettic_OTC::defaults(), '', false); + if (false === get_option('ettic_otc_settings')) { + add_option('ettic_otc_settings', Ettic_OTC::defaults(), '', false); } // Custom tables. @@ -72,8 +72,8 @@ // Stamp the schema version on a true first install only. Future schema // changes (none today) would bump this constant and re-check here. - if (false === get_option('opentrust_db_version', false)) { - update_option('opentrust_db_version', ETTIC_OTC_DB_VERSION, false); + if (false === get_option('ettic_otc_db_version', false)) { + update_option('ettic_otc_db_version', ETTIC_OTC_DB_VERSION, false); } // Seed default FAQs on first activation. Gated internally so deletions diff --git a/templates/chat.php b/templates/chat.php index df351a7..457cb91 100644 --- a/templates/chat.php +++ b/templates/chat.php @@ -33,7 +33,7 @@ $ot_max_len = (int) ($ot_settings['ai_max_message_length'] ?? 1000); $ot_ts_key = !empty($ot_settings['ai_turnstile_enabled']) ? (string) ($ot_settings['turnstile_site_key'] ?? '') : ''; -$ot_rest_url = esc_url_raw(rest_url('opentrust/v1/chat')); +$ot_rest_url = esc_url_raw(rest_url('ettic-otc/v1/chat')); $ot_nonce = wp_create_nonce('wp_rest'); // Contrast-safe text color against the user's accent color. @@ -81,17 +81,17 @@ (int) $ot_hsl['l'], $ot_accent_contrast === '#ffffff' ? '#ffffff' : '#111827' ); - wp_register_style('opentrust-frontend', plugins_url('assets/css/frontend.css', ETTIC_OTC_PLUGIN_FILE), [], ETTIC_OTC_VERSION); - wp_register_style('opentrust-chat', plugins_url('assets/css/chat.css', ETTIC_OTC_PLUGIN_FILE), ['opentrust-frontend'], ETTIC_OTC_VERSION); - wp_enqueue_style('opentrust-chat'); - wp_add_inline_style('opentrust-chat', $ot_root_vars); - wp_print_styles(['opentrust-frontend', 'opentrust-chat']); + wp_register_style('ettic-otc-frontend', plugins_url('assets/css/frontend.css', ETTIC_OTC_PLUGIN_FILE), [], ETTIC_OTC_VERSION); + wp_register_style('ettic-otc-chat', plugins_url('assets/css/chat.css', ETTIC_OTC_PLUGIN_FILE), ['ettic-otc-frontend'], ETTIC_OTC_VERSION); + wp_enqueue_style('ettic-otc-chat'); + wp_add_inline_style('ettic-otc-chat', $ot_root_vars); + wp_print_styles(['ettic-otc-frontend', 'ettic-otc-chat']); ?> 'defer']); - wp_print_scripts('opentrust-turnstile'); + wp_register_script('ettic-otc-turnstile', 'https://challenges.cloudflare.com/turnstile/v0/api.js', [], null, ['strategy' => 'defer']); + wp_print_scripts('ettic-otc-turnstile'); ?> @@ -158,7 +158,7 @@
@@ -362,14 +362,14 @@ ); wp_register_script( - 'opentrust-chat', + 'ettic-otc-chat', plugins_url('assets/js/chat.js', ETTIC_OTC_PLUGIN_FILE), [], ETTIC_OTC_VERSION, ['in_footer' => true, 'strategy' => 'defer'] ); - wp_enqueue_script('opentrust-chat'); - wp_print_scripts(['opentrust-chat']); + wp_enqueue_script('ettic-otc-chat'); + wp_print_scripts(['ettic-otc-chat']); ?> diff --git a/templates/trust-center.php b/templates/trust-center.php index 1145c2f..b399e28 100644 --- a/templates/trust-center.php +++ b/templates/trust-center.php @@ -90,10 +90,10 @@ (int) $ot_accent_l_safe, $ot_accent_contrast === '#ffffff' ? '#ffffff' : '#111827' ); - wp_register_style('opentrust-frontend', plugins_url('assets/css/frontend.css', ETTIC_OTC_PLUGIN_FILE), [], ETTIC_OTC_VERSION); - wp_enqueue_style('opentrust-frontend'); - wp_add_inline_style('opentrust-frontend', $ot_root_vars); - wp_print_styles(['opentrust-frontend']); + wp_register_style('ettic-otc-frontend', plugins_url('assets/css/frontend.css', ETTIC_OTC_PLUGIN_FILE), [], ETTIC_OTC_VERSION); + wp_enqueue_style('ettic-otc-frontend'); + wp_add_inline_style('ettic-otc-frontend', $ot_root_vars); + wp_print_styles(['ettic-otc-frontend']); ?> @@ -226,14 +226,14 @@ true, 'strategy' => 'defer'] ); - wp_enqueue_script('opentrust-frontend'); - wp_print_scripts(['opentrust-frontend']); + wp_enqueue_script('ettic-otc-frontend'); + wp_print_scripts(['ettic-otc-frontend']); ?> diff --git a/uninstall.php b/uninstall.php index 0dfe9b5..6832c55 100644 --- a/uninstall.php +++ b/uninstall.php @@ -21,11 +21,11 @@ // here. The list below MUST stay in sync with that constant; if a CPT is // added or renamed there, mirror the change here. $ot_post_types = [ - 'opentr_policy', - 'opentr_subprocessor', - 'opentr_certification', - 'opentr_data_practice', - 'opentr_faq', + 'eotc_policy', + 'eotc_subprocessor', + 'eotc_certification', + 'eotc_data_practice', + 'eotc_faq', ]; foreach ($ot_post_types as $ot_post_type) { @@ -43,56 +43,56 @@ // Drop chat log table. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared -- DDL with dynamic table prefix cannot use prepare() -$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}opentrust_chat_log"); +$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}ettic_otc_chat_log"); // Unschedule chat log purge cron. -$ot_timestamp = wp_next_scheduled('opentrust_chat_log_purge'); +$ot_timestamp = wp_next_scheduled('ettic_otc_chat_log_purge'); if ($ot_timestamp) { - wp_unschedule_event($ot_timestamp, 'opentrust_chat_log_purge'); + wp_unschedule_event($ot_timestamp, 'ettic_otc_chat_log_purge'); } // Unschedule AI model-list refresh cron. -wp_clear_scheduled_hook('opentrust_ai_models_refresh'); +wp_clear_scheduled_hook('ettic_otc_ai_models_refresh'); // Clear any pending policy-summary single-events. Pending events would otherwise // fire post-uninstall and fatal because the Ettic_OTC_Chat_Summarizer class is // gone — wp_clear_scheduled_hook() removes every scheduled occurrence. -wp_clear_scheduled_hook('opentrust_generate_policy_summary'); +wp_clear_scheduled_hook('ettic_otc_generate_policy_summary'); // Clear any pending import-preview cleanup single-events. The handler lives on // Ettic_OTC_Admin_Tools, which won't load post-uninstall. -wp_clear_scheduled_hook('opentrust_io_preview_cleanup'); +wp_clear_scheduled_hook('ettic_otc_io_preview_cleanup'); // Delete plugin options. -delete_option('opentrust_settings'); -delete_option('opentrust_provider_keys'); -delete_option('opentrust_db_version'); -delete_option('opentrust_cache_version'); -delete_option('opentrust_faqs_seeded'); +delete_option('ettic_otc_settings'); +delete_option('ettic_otc_provider_keys'); +delete_option('ettic_otc_db_version'); +delete_option('ettic_otc_cache_version'); +delete_option('ettic_otc_faqs_seeded'); // Delete orphaned post and user meta the CPT-post deletion above does not // reach. The import dedupe marker lives on attachment posts (never an // Ettic_OTC CPT), and the review-notice dismissal lives in user meta. Both -// the current `_opentrust_*` keys and the legacy `_ot_*` key are cleared — +// the current `_ettic_otc_*` keys and the legacy `_ot_*` key are cleared — // the latter covers an install removed before the v4→v5 key migration ran. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- One-shot uninstall cleanup, fixed key list, no user input. -$wpdb->query("DELETE FROM {$wpdb->postmeta} WHERE meta_key IN ('_opentrust_import_sha256', '_ot_import_sha256')"); +$wpdb->query("DELETE FROM {$wpdb->postmeta} WHERE meta_key IN ('_ettic_otc_import_sha256', '_ot_import_sha256')"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- One-shot uninstall cleanup, fixed key list, no user input. -$wpdb->query("DELETE FROM {$wpdb->usermeta} WHERE meta_key = '_opentrust_review_dismissed_v1'"); +$wpdb->query("DELETE FROM {$wpdb->usermeta} WHERE meta_key = '_ettic_otc_review_dismissed_v1'"); // Clean up any transients. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- Bulk cleanup of plugin transients on uninstall, no user input -$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_opentrust_%' OR option_name LIKE '_transient_timeout_opentrust_%'"); +$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_ettic_otc_%' OR option_name LIKE '_transient_timeout_ettic_otc_%'"); // Sweep the import-stash directory. Pre-1.1.0 installs created files directly -// under wp-content/uploads/opentrust-tmp/. From 1.1.0 onward wp_handle_upload() +// under wp-content/uploads/ettic-otc-tmp/. From 1.1.0 onward wp_handle_upload() // (scoped via an upload_dir filter) also lands here, so the runtime path is // the same as the legacy path. Walk depth-first to cover any nested layout — // the legacy structure was flat in practice but we cannot rely on that, and // orphaned import-preview ZIPs may have collected here over time. $ot_uploads = wp_upload_dir(); if (!empty($ot_uploads['basedir'])) { - $ot_stash = rtrim((string) $ot_uploads['basedir'], '/') . '/opentrust-tmp'; + $ot_stash = rtrim((string) $ot_uploads['basedir'], '/') . '/ettic-otc-tmp'; if (is_dir($ot_stash)) { try { $ot_iterator = new RecursiveIteratorIterator( diff --git a/wpml-config.xml b/wpml-config.xml index b07a412..8d06d30 100644 --- a/wpml-config.xml +++ b/wpml-config.xml @@ -17,68 +17,68 @@ --> - opentr_policy - opentr_certification - opentr_subprocessor - opentr_data_practice + eotc_policy + eotc_certification + eotc_subprocessor + eotc_data_practice - _opentrust_cert_issuing_body - _opentrust_cert_description + _ettic_otc_cert_issuing_body + _ettic_otc_cert_description - _opentrust_cert_type - _opentrust_cert_status - _opentrust_cert_issue_date - _opentrust_cert_expiry_date - _opentrust_cert_badge_id - _opentrust_cert_artifact_id + _ettic_otc_cert_type + _ettic_otc_cert_status + _ettic_otc_cert_issue_date + _ettic_otc_cert_expiry_date + _ettic_otc_cert_badge_id + _ettic_otc_cert_artifact_id - _opentrust_policy_category - _opentrust_policy_effective_date - _opentrust_policy_review_date - _opentrust_policy_sort_order + _ettic_otc_policy_category + _ettic_otc_policy_effective_date + _ettic_otc_policy_review_date + _ettic_otc_policy_sort_order - _opentrust_policy_ref_id - _opentrust_policy_citations - _opentrust_policy_attachment_id + _ettic_otc_policy_ref_id + _ettic_otc_policy_citations + _ettic_otc_policy_attachment_id - _opentrust_policy_chat_summary - _opentrust_policy_chat_summary_updated_at - _opentrust_policy_chat_summary_origin + _ettic_otc_policy_chat_summary + _ettic_otc_policy_chat_summary_updated_at + _ettic_otc_policy_chat_summary_origin - _opentrust_sub_purpose - _opentrust_sub_data_processed - _opentrust_sub_country + _ettic_otc_sub_purpose + _ettic_otc_sub_data_processed + _ettic_otc_sub_country - _opentrust_sub_website - _opentrust_sub_dpa_signed + _ettic_otc_sub_website + _ettic_otc_sub_dpa_signed - _opentrust_dp_purpose - _opentrust_dp_retention_period - _opentrust_dp_data_items - _opentrust_dp_shared_with - _opentrust_dp_legal_basis - _opentrust_dp_sort_order + _ettic_otc_dp_purpose + _ettic_otc_dp_retention_period + _ettic_otc_dp_data_items + _ettic_otc_dp_shared_with + _ettic_otc_dp_legal_basis + _ettic_otc_dp_sort_order - _opentrust_dp_collection_method - _opentrust_dp_data_type - _opentrust_dp_is_sensitive + _ettic_otc_dp_collection_method + _ettic_otc_dp_data_type + _ettic_otc_dp_is_sensitive From b92c9d81ea033921d8638443eb894b423657ce78 Mon Sep 17 00:00:00 2001 From: r00bbert <280805750+r00bbert@users.noreply.github.com> Date: Sun, 17 May 2026 14:30:29 +0200 Subject: [PATCH 05/18] Phase 6+7: text-domain rename + language file regeneration - Replace 'opentrust' text-domain literal with 'open-trust-center-by-ettic' across all PHP source (535 calls) - Rename languages/opentrust.{pot,nl_NL.po,nl_NL.mo} to languages/open-trust-center-by-ettic.* to match new text domain - Regenerate POT via wp i18n make-pot (new headers, new file refs) - msgmerge nl_NL.po against new POT; existing translations carried forward as fuzzy where strings remained similar - Update PO header: Project-Id-Version, Last-Translator, X-Domain - Rebuild MO from updated PO Fuzzy translations need a human review pass before they go in MO (msgfmt default skips fuzzy). For v1.2.0 ship the .mo as-is; nl_NL translator can fill in the new strings in a follow-up. --- includes/class-ettic-otc-admin-ai.php | 166 +- includes/class-ettic-otc-admin-questions.php | 64 +- includes/class-ettic-otc-admin-review.php | 20 +- includes/class-ettic-otc-admin-settings.php | 122 +- includes/class-ettic-otc-admin-tools.php | 82 +- includes/class-ettic-otc-admin.php | 50 +- includes/class-ettic-otc-chat.php | 36 +- includes/class-ettic-otc-cpt.php | 312 +- includes/class-ettic-otc-io.php | 28 +- includes/class-ettic-otc-render.php | 54 +- includes/class-ettic-otc-version.php | 22 +- includes/data/faq-catalog.php | 40 +- ...lass-ettic-otc-chat-provider-anthropic.php | 12 +- .../class-ettic-otc-chat-provider-openai.php | 6 +- ...ass-ettic-otc-chat-provider-openrouter.php | 2 +- .../class-ettic-otc-chat-provider.php | 56 +- languages/open-trust-center-by-ettic-nl_NL.mo | Bin 0 -> 543 bytes languages/open-trust-center-by-ettic-nl_NL.po | 2955 +++++++++++++++++ ...ust.pot => open-trust-center-by-ettic.pot} | 1079 +++--- languages/opentrust-nl_NL.mo | Bin 9334 -> 0 bytes languages/opentrust-nl_NL.po | 2496 -------------- templates/chat.php | 108 +- templates/partials/certifications.php | 14 +- templates/partials/chat-budget-exhausted.php | 8 +- templates/partials/chat-empty-state.php | 8 +- templates/partials/contact.php | 20 +- templates/partials/data-practices.php | 14 +- templates/partials/faq.php | 6 +- templates/partials/hero.php | 10 +- templates/partials/policies.php | 26 +- templates/partials/policy-single.php | 32 +- templates/partials/subprocessors.php | 22 +- templates/trust-center.php | 28 +- 33 files changed, 4180 insertions(+), 3718 deletions(-) create mode 100644 languages/open-trust-center-by-ettic-nl_NL.mo create mode 100644 languages/open-trust-center-by-ettic-nl_NL.po rename languages/{opentrust.pot => open-trust-center-by-ettic.pot} (65%) delete mode 100644 languages/opentrust-nl_NL.mo delete mode 100644 languages/opentrust-nl_NL.po diff --git a/includes/class-ettic-otc-admin-ai.php b/includes/class-ettic-otc-admin-ai.php index 41a4c06..6d803d5 100644 --- a/includes/class-ettic-otc-admin-ai.php +++ b/includes/class-ettic-otc-admin-ai.php @@ -75,12 +75,12 @@ public function render_ai_tab(array $settings): void { ?>
- +

%s. Only Anthropic uses a structural Citations API — every other provider relies on prompted citation tags the model can ignore or fabricate. For a published trust center, switch to Anthropic below.', 'opentrust'), ['strong' => []]), + wp_kses(__('You are currently using %s. Only Anthropic uses a structural Citations API — every other provider relies on prompted citation tags the model can ignore or fabricate. For a published trust center, switch to Anthropic below.', 'open-trust-center-by-ettic'), ['strong' => []]), esc_html(ucfirst($active_provider)) ); ?> @@ -91,19 +91,19 @@ public function render_ai_tab(array $settings): void {

Anthropic Claude with the native Citations API to answer visitor questions about your trust center. Every claim the assistant makes is tied to an exact quote from one of your published documents — so no policy text is invented and nothing is paraphrased into something you did not actually publish.', 'opentrust'), + __('Ettic_OTC uses Anthropic Claude with the native Citations API to answer visitor questions about your trust center. Every claim the assistant makes is tied to an exact quote from one of your published documents — so no policy text is invented and nothing is paraphrased into something you did not actually publish.', 'open-trust-center-by-ettic'), ['strong' => []] ); ?>

- +

compliance surface. If the assistant invents a security commitment you never made, that is not a UX papercut — it is a misrepresentation of your security posture, and your customers and auditors will hold you to it.', 'opentrust'), + __('A trust center is a compliance surface. If the assistant invents a security commitment you never made, that is not a UX papercut — it is a misrepresentation of your security posture, and your customers and auditors will hold you to it.', 'open-trust-center-by-ettic'), ['strong' => []] ); ?> @@ -111,13 +111,13 @@ public function render_ai_tab(array $settings): void {

only major provider that exposes a structural Citations API. Documents are sent as typed blocks and the model emits citations as first-class events containing the exact source document and the exact quoted text. The model literally cannot return a citation for text that is not in your source documents.', 'opentrust'), + __('Anthropic is the only major provider that exposes a structural Citations API. Documents are sent as typed blocks and the model emits citations as first-class events containing the exact source document and the exact quoted text. The model literally cannot return a citation for text that is not in your source documents.', 'open-trust-center-by-ettic'), ['strong' => []] ); ?>

- +

@@ -160,19 +160,19 @@ private function render_summary_backfill_banner(array $settings, bool $has_activ '%d policy is missing an AI summary.', '%d policies are missing AI summaries.', $missing, - 'opentrust' + 'open-trust-center-by-ettic' ) ), (int) $missing ); ?> - +

- +
' . esc_html__('Choose a provider and add your key', 'opentrust') . ''; + echo '

' . esc_html__('Choose a provider and add your key', 'open-trust-center-by-ettic') . '

'; echo '
'; foreach ($providers as $provider) { $this->render_provider_card($provider, $stored_keys, $active_provider, 'advanced'); @@ -208,22 +208,22 @@ private function render_ai_provider_picker(array $settings, array $stored_keys): $is_anthropic_active = $active_provider === 'anthropic' && isset($stored_keys['anthropic']); $advanced_open = $active_provider !== '' && $active_provider !== 'anthropic'; ?> -

+

render_provider_card($primary, $stored_keys, $active_provider, 'primary'); ?>
> - +
- +

- +

- - + +

@@ -262,13 +262,13 @@ private function render_provider_card(array $provider, array $stored_keys, strin

- +

- +

@@ -276,7 +276,7 @@ private function render_provider_card(array $provider, array $stored_keys, strin

@@ -289,8 +289,8 @@ private function render_provider_card(array $provider, array $stored_keys, strin - @@ -300,11 +300,11 @@ private function render_provider_card(array $provider, array $stored_keys, strin @@ -343,7 +343,7 @@ private function render_ai_settings_form(array $settings): void { array_unshift($models, $snapshot); } ?> -

+

@@ -356,11 +356,11 @@ private function render_ai_settings_form(array $settings): void { - + - + - + - + - + - + - + - + - + - + @@ -484,18 +484,18 @@ private function render_ai_settings_form(array $settings): void { - + -

+

- +

- + - + - + - +
403]); + wp_die(esc_html__('You do not have permission to perform this action.', 'open-trust-center-by-ettic'), '', ['response' => 403]); } check_admin_referer('ettic_otc_ai_save_key'); @@ -663,20 +663,20 @@ public function handle_ai_save_key(): void { $adapter = Ettic_OTC_Chat_Provider::for($provider); if (!$adapter) { - $this->ai_notice('error', __('Unknown provider.', 'opentrust')); + $this->ai_notice('error', __('Unknown provider.', 'open-trust-center-by-ettic')); $this->redirect_to_ai_tab(); } if ($api_key === '') { - $this->ai_notice('error', __('API key cannot be empty.', 'opentrust')); + $this->ai_notice('error', __('API key cannot be empty.', 'open-trust-center-by-ettic')); $this->redirect_to_ai_tab(); } $result = $this->refresh_provider_cache($provider, $api_key); if (empty($result['ok'])) { - $error = $result['error'] ?? __('Validation failed.', 'opentrust'); + $error = $result['error'] ?? __('Validation failed.', 'open-trust-center-by-ettic'); /* translators: 1: provider label, 2: provider error message */ - $msg = sprintf(__('%1$s rejected the key: %2$s', 'opentrust'), $adapter->label(), $error); + $msg = sprintf(__('%1$s rejected the key: %2$s', 'open-trust-center-by-ettic'), $adapter->label(), $error); $this->ai_notice('error', $msg); $this->redirect_to_ai_tab(); } @@ -704,14 +704,14 @@ public function handle_ai_save_key(): void { Ettic_OTC_Admin_Settings::instance()->save_settings_raw($settings); /* translators: 1: provider label, 2: number of models */ - $count_msg = sprintf(__('%1$s key validated. Found %2$d model(s).', 'opentrust'), $adapter->label(), count($result['models'])); + $count_msg = sprintf(__('%1$s key validated. Found %2$d model(s).', 'open-trust-center-by-ettic'), $adapter->label(), count($result['models'])); $this->ai_notice('success', $count_msg); $this->redirect_to_ai_tab(); } public function handle_ai_forget_key(): void { if (!current_user_can('manage_options')) { - wp_die(esc_html__('You do not have permission to perform this action.', 'opentrust'), '', ['response' => 403]); + wp_die(esc_html__('You do not have permission to perform this action.', 'open-trust-center-by-ettic'), '', ['response' => 403]); } check_admin_referer('ettic_otc_ai_forget_key'); @@ -719,7 +719,7 @@ public function handle_ai_forget_key(): void { $adapter = Ettic_OTC_Chat_Provider::for($provider); if (!$adapter) { - $this->ai_notice('error', __('Unknown provider.', 'opentrust')); + $this->ai_notice('error', __('Unknown provider.', 'open-trust-center-by-ettic')); $this->redirect_to_ai_tab(); } @@ -742,34 +742,34 @@ public function handle_ai_forget_key(): void { Ettic_OTC_Admin_Settings::instance()->save_settings_raw($settings); } - $this->ai_notice('success', __('Key removed.', 'opentrust')); + $this->ai_notice('success', __('Key removed.', 'open-trust-center-by-ettic')); $this->redirect_to_ai_tab(); } public function handle_ai_refresh_models(): void { if (!current_user_can('manage_options')) { - wp_die(esc_html__('You do not have permission to perform this action.', 'opentrust'), '', ['response' => 403]); + wp_die(esc_html__('You do not have permission to perform this action.', 'open-trust-center-by-ettic'), '', ['response' => 403]); } check_admin_referer('ettic_otc_ai_refresh_models'); $provider = isset($_GET['provider']) ? sanitize_key((string) wp_unslash($_GET['provider'])) : ''; $adapter = Ettic_OTC_Chat_Provider::for($provider); if (!$adapter) { - $this->ai_notice('error', __('Unknown provider.', 'opentrust')); + $this->ai_notice('error', __('Unknown provider.', 'open-trust-center-by-ettic')); $this->redirect_to_ai_tab(); } $api_key = Ettic_OTC_Chat_Secrets::get($provider); if ($api_key === null) { - $this->ai_notice('error', __('No key on file for this provider.', 'opentrust')); + $this->ai_notice('error', __('No key on file for this provider.', 'open-trust-center-by-ettic')); $this->redirect_to_ai_tab(); } $result = $this->refresh_provider_cache($provider, $api_key); if (empty($result['ok'])) { - $error = $result['error'] ?? __('Refresh failed.', 'opentrust'); + $error = $result['error'] ?? __('Refresh failed.', 'open-trust-center-by-ettic'); /* translators: %s: error message from the provider */ - $this->ai_notice('error', sprintf(__('Refresh failed: %s', 'opentrust'), $error)); + $this->ai_notice('error', sprintf(__('Refresh failed: %s', 'open-trust-center-by-ettic'), $error)); $this->redirect_to_ai_tab(); } @@ -779,7 +779,7 @@ public function handle_ai_refresh_models(): void { Ettic_OTC_Admin_Settings::instance()->save_settings_raw($settings); /* translators: %d: number of models */ - $this->ai_notice('success', sprintf(__('Model list refreshed. Found %d model(s).', 'opentrust'), count($result['models']))); + $this->ai_notice('success', sprintf(__('Model list refreshed. Found %d model(s).', 'open-trust-center-by-ettic'), count($result['models']))); $this->redirect_to_ai_tab(); } @@ -793,7 +793,7 @@ public function handle_ai_refresh_models(): void { */ public function handle_ai_summarize_sweep(): void { if (!current_user_can('manage_options')) { - wp_die(esc_html__('You do not have permission to perform this action.', 'opentrust'), '', ['response' => 403]); + wp_die(esc_html__('You do not have permission to perform this action.', 'open-trust-center-by-ettic'), '', ['response' => 403]); } check_admin_referer('ettic_otc_ai_summarize_sweep'); @@ -813,11 +813,11 @@ public function handle_ai_summarize_sweep(): void { 'Queued %d policy for AI summary generation. Summaries will appear over the next minute.', 'Queued %d policies for AI summary generation. Summaries will appear over the next few minutes.', $count, - 'opentrust' + 'open-trust-center-by-ettic' ), (int) $count ) - : __('All policies already have up-to-date AI summaries.', 'opentrust'), + : __('All policies already have up-to-date AI summaries.', 'open-trust-center-by-ettic'), ], MINUTE_IN_SECONDS ); diff --git a/includes/class-ettic-otc-admin-questions.php b/includes/class-ettic-otc-admin-questions.php index c61f681..9ebe153 100644 --- a/includes/class-ettic-otc-admin-questions.php +++ b/includes/class-ettic-otc-admin-questions.php @@ -84,29 +84,29 @@ public function render_page(): void { ?>
-

+

- +

@@ -114,46 +114,46 @@ public function render_page(): void {
- - + +
- +
- +
- +
- - - + + +
- - - - - - + + + + + + - + refused ? 'background:#fef9c3' : ''; @@ -162,7 +162,7 @@ public function render_page(): void { @@ -206,9 +206,9 @@ public function render_page(): void {
-

-

- +

+

+

403]); + wp_die(esc_html__('You do not have permission to perform this action.', 'open-trust-center-by-ettic'), '', ['response' => 403]); } check_admin_referer('ettic_otc_ai_questions_export'); @@ -261,7 +261,7 @@ public function handle_export(): void { public function handle_clear(): void { if (!current_user_can('manage_options')) { - wp_die(esc_html__('You do not have permission to perform this action.', 'opentrust'), '', ['response' => 403]); + wp_die(esc_html__('You do not have permission to perform this action.', 'open-trust-center-by-ettic'), '', ['response' => 403]); } check_admin_referer('ettic_otc_ai_questions_clear'); @@ -269,7 +269,7 @@ public function handle_clear(): void { set_transient( 'ettic_otc_ai_notice_' . get_current_user_id(), - ['type' => 'success', 'message' => __('Question log cleared.', 'opentrust')], + ['type' => 'success', 'message' => __('Question log cleared.', 'open-trust-center-by-ettic')], MINUTE_IN_SECONDS ); wp_safe_redirect(admin_url('admin.php?page=ettic-otc-questions')); @@ -278,7 +278,7 @@ public function handle_clear(): void { public function handle_toggle_logging(): void { if (!current_user_can('manage_options')) { - wp_die(esc_html__('You do not have permission to perform this action.', 'opentrust'), '', ['response' => 403]); + wp_die(esc_html__('You do not have permission to perform this action.', 'open-trust-center-by-ettic'), '', ['response' => 403]); } check_admin_referer('ettic_otc_ai_toggle_logging'); @@ -288,7 +288,7 @@ public function handle_toggle_logging(): void { set_transient( 'ettic_otc_ai_notice_' . get_current_user_id(), - ['type' => 'success', 'message' => $settings['ai_logging_enabled'] ? __('Logging enabled.', 'opentrust') : __('Logging disabled.', 'opentrust')], + ['type' => 'success', 'message' => $settings['ai_logging_enabled'] ? __('Logging enabled.', 'open-trust-center-by-ettic') : __('Logging disabled.', 'open-trust-center-by-ettic')], MINUTE_IN_SECONDS ); wp_safe_redirect(admin_url('admin.php?page=ettic-otc-questions')); diff --git a/includes/class-ettic-otc-admin-review.php b/includes/class-ettic-otc-admin-review.php index eb306a9..b966d42 100644 --- a/includes/class-ettic-otc-admin-review.php +++ b/includes/class-ettic-otc-admin-review.php @@ -78,7 +78,7 @@ public function footer_text(string $text): string { $link = sprintf( '%s', esc_url(self::review_url()), - esc_html__('review on WordPress.org', 'opentrust') + esc_html__('review on WordPress.org', 'open-trust-center-by-ettic') ); // The static English string contains no HTML; the only insertion is @@ -86,7 +86,7 @@ public function footer_text(string $text): string { // the result — same risk model as core's admin_footer_text usage. return sprintf( /* translators: %s: link to the WordPress.org reviews page */ - __('Ettic_OTC is built and maintained in the open. If it is helping your team, a %s keeps the project moving.', 'opentrust'), + __('Ettic_OTC is built and maintained in the open. If it is helping your team, a %s keeps the project moving.', 'open-trust-center-by-ettic'), $link ); } @@ -112,18 +112,18 @@ public function render_milestone_notice(): void { ?> @@ -165,7 +165,7 @@ private function should_show_milestone_notice(): bool { public function handle_dismiss(): void { if (!current_user_can('manage_options')) { wp_die( - esc_html__('You do not have permission to dismiss this notice.', 'opentrust'), + esc_html__('You do not have permission to dismiss this notice.', 'open-trust-center-by-ettic'), '', ['response' => 403] ); @@ -191,7 +191,7 @@ public function handle_dismiss(): void { /** * Match the scoping rule used by render_plain_permalinks_notice in - * Ettic_OTC_Admin: any screen whose id contains "opentrust" plus the + * Ettic_OTC_Admin: any screen whose id contains "open-trust-center-by-ettic" plus the * five content CPTs. Identical pattern keeps both notices in lockstep. */ private static function is_ettic_otc_screen(): bool { @@ -203,7 +203,7 @@ private static function is_ettic_otc_screen(): bool { return false; } - return str_contains((string) $screen->id, 'opentrust') + return str_contains((string) $screen->id, 'open-trust-center-by-ettic') || in_array($screen->post_type, Ettic_OTC_CPT::CORPUS, true); } diff --git a/includes/class-ettic-otc-admin-settings.php b/includes/class-ettic-otc-admin-settings.php index 623926f..6d29e0e 100644 --- a/includes/class-ettic-otc-admin-settings.php +++ b/includes/class-ettic-otc-admin-settings.php @@ -52,93 +52,93 @@ public function register_settings(): void { // ── General tab ────────────────────────────────────────────── add_settings_section( 'ettic_otc_general', - __('General Settings', 'opentrust'), + __('General Settings', 'open-trust-center-by-ettic'), fn() => null, 'ettic-otc-settings-general' ); - $this->add_field('endpoint_slug', __('Endpoint Slug', 'opentrust'), 'render_text_field', 'ettic_otc_general', 'ettic-otc-settings-general', [ - 'description' => __('The URL path for your trust center (e.g., "trust-center" = yoursite.com/trust-center/).', 'opentrust'), + $this->add_field('endpoint_slug', __('Endpoint Slug', 'open-trust-center-by-ettic'), 'render_text_field', 'ettic_otc_general', 'ettic-otc-settings-general', [ + 'description' => __('The URL path for your trust center (e.g., "trust-center" = yoursite.com/trust-center/).', 'open-trust-center-by-ettic'), ]); - $this->add_field('page_title', __('Page Title', 'opentrust'), 'render_text_field', 'ettic_otc_general', 'ettic-otc-settings-general'); + $this->add_field('page_title', __('Page Title', 'open-trust-center-by-ettic'), 'render_text_field', 'ettic_otc_general', 'ettic-otc-settings-general'); - $this->add_field('company_name', __('Company Name', 'opentrust'), 'render_text_field', 'ettic_otc_general', 'ettic-otc-settings-general'); + $this->add_field('company_name', __('Company Name', 'open-trust-center-by-ettic'), 'render_text_field', 'ettic_otc_general', 'ettic-otc-settings-general'); - $this->add_field('tagline', __('Tagline', 'opentrust'), 'render_textarea_field', 'ettic_otc_general', 'ettic-otc-settings-general', [ - 'description' => __('A short description displayed below the company name in the hero section.', 'opentrust'), + $this->add_field('tagline', __('Tagline', 'open-trust-center-by-ettic'), 'render_textarea_field', 'ettic_otc_general', 'ettic-otc-settings-general', [ + 'description' => __('A short description displayed below the company name in the hero section.', 'open-trust-center-by-ettic'), ]); // Branding section (General tab). add_settings_section( 'ettic_otc_branding', - __('Branding', 'opentrust'), + __('Branding', 'open-trust-center-by-ettic'), fn() => null, 'ettic-otc-settings-general' ); - $this->add_field('logo_id', __('Logo', 'opentrust'), 'render_logo_field', 'ettic_otc_branding', 'ettic-otc-settings-general'); - $this->add_field('avatar_id', __('AI Avatar', 'opentrust'), 'render_avatar_field', 'ettic_otc_branding', 'ettic-otc-settings-general'); + $this->add_field('logo_id', __('Logo', 'open-trust-center-by-ettic'), 'render_logo_field', 'ettic_otc_branding', 'ettic-otc-settings-general'); + $this->add_field('avatar_id', __('AI Avatar', 'open-trust-center-by-ettic'), 'render_avatar_field', 'ettic_otc_branding', 'ettic-otc-settings-general'); - $this->add_field('accent_color', __('Accent Color', 'opentrust'), 'render_color_field', 'ettic_otc_branding', 'ettic-otc-settings-general', [ - 'description' => __('Used for buttons, links, and highlights. Choose a color that matches your brand.', 'opentrust'), + $this->add_field('accent_color', __('Accent Color', 'open-trust-center-by-ettic'), 'render_color_field', 'ettic_otc_branding', 'ettic-otc-settings-general', [ + 'description' => __('Used for buttons, links, and highlights. Choose a color that matches your brand.', 'open-trust-center-by-ettic'), ]); - $this->add_field('show_powered_by', __('Credit Link', 'opentrust'), 'render_show_powered_by_field', 'ettic_otc_branding', 'ettic-otc-settings-general'); + $this->add_field('show_powered_by', __('Credit Link', 'open-trust-center-by-ettic'), 'render_show_powered_by_field', 'ettic_otc_branding', 'ettic-otc-settings-general'); // Sections visibility (General tab). add_settings_section( 'ettic_otc_sections', - __('Visible Sections', 'opentrust'), - fn() => print('

' . esc_html__('Choose which sections to display on the trust center.', 'opentrust') . '

'), + __('Visible Sections', 'open-trust-center-by-ettic'), + fn() => print('

' . esc_html__('Choose which sections to display on the trust center.', 'open-trust-center-by-ettic') . '

'), 'ettic-otc-settings-general' ); - $this->add_field('sections_visible', __('Sections', 'opentrust'), 'render_sections_field', 'ettic_otc_sections', 'ettic-otc-settings-general'); + $this->add_field('sections_visible', __('Sections', 'open-trust-center-by-ettic'), 'render_sections_field', 'ettic_otc_sections', 'ettic-otc-settings-general'); // ── Contact tab ────────────────────────────────────────────── // Fields are optional — the frontend block renders only when at least one field below is populated. add_settings_section( 'ettic_otc_contact', - __('Get in touch', 'opentrust'), - fn() => print('

' . esc_html__('Publish a dark-accent "Get in touch" block on the trust center. Every field is optional — the block only appears if at least one is filled in.', 'opentrust') . '

'), + __('Get in touch', 'open-trust-center-by-ettic'), + fn() => print('

' . esc_html__('Publish a dark-accent "Get in touch" block on the trust center. Every field is optional — the block only appears if at least one is filled in.', 'open-trust-center-by-ettic') . '

'), 'ettic-otc-settings-contact' ); - $this->add_field('company_description', __('Company Description', 'opentrust'), 'render_textarea_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ - 'description' => __('Two or three sentences describing what the company does. Rendered under the "Get in touch" section title.', 'opentrust'), + $this->add_field('company_description', __('Company Description', 'open-trust-center-by-ettic'), 'render_textarea_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ + 'description' => __('Two or three sentences describing what the company does. Rendered under the "Get in touch" section title.', 'open-trust-center-by-ettic'), ]); - $this->add_field('dpo_name', __('DPO Name', 'opentrust'), 'render_text_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ - 'description' => __('Data Protection Officer name. Required under GDPR for many organisations.', 'opentrust'), + $this->add_field('dpo_name', __('DPO Name', 'open-trust-center-by-ettic'), 'render_text_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ + 'description' => __('Data Protection Officer name. Required under GDPR for many organisations.', 'open-trust-center-by-ettic'), ]); - $this->add_field('dpo_email', __('DPO Email', 'opentrust'), 'render_email_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ - 'description' => __('Dedicated DPO mailbox. Rendered as a mailto link.', 'opentrust'), + $this->add_field('dpo_email', __('DPO Email', 'open-trust-center-by-ettic'), 'render_email_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ + 'description' => __('Dedicated DPO mailbox. Rendered as a mailto link.', 'open-trust-center-by-ettic'), ]); - $this->add_field('security_email', __('Security Contact Email', 'opentrust'), 'render_email_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ - 'description' => __('For vulnerability reports and security questions. Often separate from the DPO.', 'opentrust'), + $this->add_field('security_email', __('Security Contact Email', 'open-trust-center-by-ettic'), 'render_email_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ + 'description' => __('For vulnerability reports and security questions. Often separate from the DPO.', 'open-trust-center-by-ettic'), ]); - $this->add_field('contact_form_url', __('Contact Form URL', 'opentrust'), 'render_url_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ - 'description' => __('Optional link to a gated contact form.', 'opentrust'), + $this->add_field('contact_form_url', __('Contact Form URL', 'open-trust-center-by-ettic'), 'render_url_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ + 'description' => __('Optional link to a gated contact form.', 'open-trust-center-by-ettic'), ]); - $this->add_field('contact_address', __('Mailing Address', 'opentrust'), 'render_textarea_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ - 'description' => __('Postal address for formal GDPR / legal notices.', 'opentrust'), + $this->add_field('contact_address', __('Mailing Address', 'open-trust-center-by-ettic'), 'render_textarea_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ + 'description' => __('Postal address for formal GDPR / legal notices.', 'open-trust-center-by-ettic'), ]); - $this->add_field('pgp_key_url', __('PGP Public Key URL', 'opentrust'), 'render_url_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ - 'description' => __('Optional link to your security team\'s PGP public key.', 'opentrust'), + $this->add_field('pgp_key_url', __('PGP Public Key URL', 'open-trust-center-by-ettic'), 'render_url_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ + 'description' => __('Optional link to your security team\'s PGP public key.', 'open-trust-center-by-ettic'), ]); - $this->add_field('company_registration', __('Company Registration Number', 'opentrust'), 'render_text_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ - 'description' => __('KvK (NL), Companies House (UK), Handelsregister (DE), EIN (US), or equivalent business registration.', 'opentrust'), + $this->add_field('company_registration', __('Company Registration Number', 'open-trust-center-by-ettic'), 'render_text_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ + 'description' => __('KvK (NL), Companies House (UK), Handelsregister (DE), EIN (US), or equivalent business registration.', 'open-trust-center-by-ettic'), ]); - $this->add_field('vat_number', __('VAT / Tax ID', 'opentrust'), 'render_text_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ - 'description' => __('VAT number, sales-tax ID, or equivalent international tax identifier.', 'opentrust'), + $this->add_field('vat_number', __('VAT / Tax ID', 'open-trust-center-by-ettic'), 'render_text_field', 'ettic_otc_contact', 'ettic-otc-settings-contact', [ + 'description' => __('VAT number, sales-tax ID, or equivalent international tax identifier.', 'open-trust-center-by-ettic'), ]); } @@ -219,14 +219,14 @@ public function render_color_field(array $args): void { @@ -262,16 +262,16 @@ public function render_color_field(array $args): void { public function render_logo_field(array $args): void { $this->render_media_field( 'logo_id', - __('Select Logo', 'opentrust'), - __('Used in the hero and sticky nav. A white version is recommended — it sits on a dark background.', 'opentrust') + __('Select Logo', 'open-trust-center-by-ettic'), + __('Used in the hero and sticky nav. A white version is recommended — it sits on a dark background.', 'open-trust-center-by-ettic') ); } public function render_avatar_field(array $args): void { $this->render_media_field( 'avatar_id', - __('Select Avatar', 'opentrust'), - __('Square image used as the avatar on AI chat responses. Use a colored background with a light or dark favicon or logo on top.', 'opentrust') + __('Select Avatar', 'open-trust-center-by-ettic'), + __('Square image used as the avatar on AI chat responses. Use a colored background with a light or dark favicon or logo on top.', 'open-trust-center-by-ettic') ); } @@ -286,7 +286,7 @@ private function render_media_field(string $key, string $button_label, string $d - +

%s', checked($checked, true, false), - esc_html__('Show a "Powered by Open Trust Center" credit in the trust center footer.', 'opentrust') + esc_html__('Show a "Powered by Open Trust Center" credit in the trust center footer.', 'open-trust-center-by-ettic') ); printf( '

%s

', - esc_html__('Off by default. Public credits are opt-in.', 'opentrust') + esc_html__('Off by default. Public credits are opt-in.', 'open-trust-center-by-ettic') ); } @@ -311,12 +311,12 @@ public function render_sections_field(array $args): void { $visible = $settings['sections_visible'] ?? []; $sections = [ - 'certifications' => __('Certifications & Compliance', 'opentrust'), - 'policies' => __('Policies', 'opentrust'), - 'subprocessors' => __('Subprocessors', 'opentrust'), - 'data_practices' => __('Data Practices', 'opentrust'), - 'faqs' => __('FAQs', 'opentrust'), - 'contact' => __('Contact & DPO', 'opentrust'), + 'certifications' => __('Certifications & Compliance', 'open-trust-center-by-ettic'), + 'policies' => __('Policies', 'open-trust-center-by-ettic'), + 'subprocessors' => __('Subprocessors', 'open-trust-center-by-ettic'), + 'data_practices' => __('Data Practices', 'open-trust-center-by-ettic'), + 'faqs' => __('FAQs', 'open-trust-center-by-ettic'), + 'contact' => __('Contact & DPO', 'open-trust-center-by-ettic'), ]; foreach ($sections as $key => $label) { @@ -583,31 +583,31 @@ public function render_settings_page(): void {

- → +

diff --git a/includes/class-ettic-otc-admin-tools.php b/includes/class-ettic-otc-admin-tools.php index 771b153..602ff1b 100644 --- a/includes/class-ettic-otc-admin-tools.php +++ b/includes/class-ettic-otc-admin-tools.php @@ -152,7 +152,7 @@ public function render_tab(): void { $exportable = Ettic_OTC_IO::exportable_summary(); ?>

- +

@@ -160,11 +160,11 @@ public function render_tab(): void {
-

+

render_export_panel($exportable); ?>
-

+

render_import_panel(); ?>
@@ -180,19 +180,19 @@ private function render_export_panel(array $exportable): void {
- +
- + $items): $label = $this->cpt_label($cpt); $count = count($items); @@ -222,11 +222,11 @@ private function render_export_panel(array $exportable): void {

- +

- - + +

-
+

- +

- +

-

+

-

+

  • @@ -314,14 +314,14 @@ private function render_preview_screen(array $preview): void {

    - +

- - - + + + @@ -358,9 +358,9 @@ private function render_preview_screen(array $preview): void { - + - + parse_selection($_POST); if (empty($selection)) { - $this->bounce_error(__('Pick at least one record to export.', 'opentrust')); + $this->bounce_error(__('Pick at least one record to export.', 'open-trust-center-by-ettic')); return; } $manifest = Ettic_OTC_IO::build_content_manifest($selection, $include_media); @@ -412,13 +412,13 @@ public function handle_import_preview(): void { $this->guard('ettic_otc_import_preview'); if (empty($_FILES['ettic_otc_import_file']['tmp_name']) || !is_uploaded_file((string) $_FILES['ettic_otc_import_file']['tmp_name'])) { - $this->bounce_error(__('No file uploaded.', 'opentrust')); + $this->bounce_error(__('No file uploaded.', 'open-trust-center-by-ettic')); return; } $size = (int) ($_FILES['ettic_otc_import_file']['size'] ?? 0); if ($size > self::UPLOAD_MAX_MB * 1024 * 1024) { - $this->bounce_error(__('Upload exceeds size limit.', 'opentrust')); + $this->bounce_error(__('Upload exceeds size limit.', 'open-trust-center-by-ettic')); return; } @@ -511,12 +511,12 @@ public function handle_import_apply(): void { wp_delete_file((string) $preview['zip_path']); } delete_transient($stash_key); - $this->bounce_notice(__('Import cancelled.', 'opentrust'), 'success'); + $this->bounce_notice(__('Import cancelled.', 'open-trust-center-by-ettic'), 'success'); return; } if (!empty($preview['errors'])) { - $this->bounce_error(__('Import has unresolved errors.', 'opentrust')); + $this->bounce_error(__('Import has unresolved errors.', 'open-trust-center-by-ettic')); return; } @@ -529,14 +529,14 @@ public function handle_import_apply(): void { $result = Ettic_OTC_IO::apply_settings_import($manifest, $zip_path); $msg = sprintf( /* translators: %d: count */ - _n('%d setting imported.', '%d settings imported.', (int) ($result['updated'] ?? 0), 'opentrust'), + _n('%d setting imported.', '%d settings imported.', (int) ($result['updated'] ?? 0), 'open-trust-center-by-ettic'), (int) ($result['updated'] ?? 0) ); } else { $result = Ettic_OTC_IO::apply_content_import($manifest, $zip_path, $strategy); $msg = sprintf( /* translators: %1$d: created, %2$d: updated, %3$d: skipped */ - __('Imported: %1$d created, %2$d updated, %3$d skipped.', 'opentrust'), + __('Imported: %1$d created, %2$d updated, %3$d skipped.', 'open-trust-center-by-ettic'), (int) ($result['created'] ?? 0), (int) ($result['updated'] ?? 0), (int) ($result['skipped'] ?? 0) @@ -544,7 +544,7 @@ public function handle_import_apply(): void { } if (!empty($result['errors'])) { - $msg .= '
' . esc_html__('Errors:', 'opentrust') . '
' . esc_html(implode('
', (array) $result['errors'])); + $msg .= '
' . esc_html__('Errors:', 'open-trust-center-by-ettic') . '
' . esc_html(implode('
', (array) $result['errors'])); } $this->bounce_notice($msg, !empty($result['errors']) ? 'error' : 'success'); @@ -562,7 +562,7 @@ public function handle_import_apply(): void { private function guard(string $nonce_action): void { if (!current_user_can('manage_options')) { - wp_die(esc_html__('You do not have permission to perform this action.', 'opentrust'), '', ['response' => 403]); + wp_die(esc_html__('You do not have permission to perform this action.', 'open-trust-center-by-ettic'), '', ['response' => 403]); } check_admin_referer($nonce_action); } @@ -589,11 +589,11 @@ private function parse_selection(array $post): array { private function cpt_label(string $cpt): string { return match ($cpt) { - Ettic_OTC_CPT::POLICY => __('Policies', 'opentrust'), - Ettic_OTC_CPT::CERTIFICATION => __('Certifications', 'opentrust'), - Ettic_OTC_CPT::SUBPROCESSOR => __('Subprocessors', 'opentrust'), - Ettic_OTC_CPT::DATA_PRACTICE => __('Data Practices', 'opentrust'), - Ettic_OTC_CPT::FAQ => __('FAQs', 'opentrust'), + Ettic_OTC_CPT::POLICY => __('Policies', 'open-trust-center-by-ettic'), + Ettic_OTC_CPT::CERTIFICATION => __('Certifications', 'open-trust-center-by-ettic'), + Ettic_OTC_CPT::SUBPROCESSOR => __('Subprocessors', 'open-trust-center-by-ettic'), + Ettic_OTC_CPT::DATA_PRACTICE => __('Data Practices', 'open-trust-center-by-ettic'), + Ettic_OTC_CPT::FAQ => __('FAQs', 'open-trust-center-by-ettic'), default => $cpt, }; } diff --git a/includes/class-ettic-otc-admin.php b/includes/class-ettic-otc-admin.php index d49ba4e..4845726 100644 --- a/includes/class-ettic-otc-admin.php +++ b/includes/class-ettic-otc-admin.php @@ -53,8 +53,8 @@ public function register_menu(): void { $settings_page = [Ettic_OTC_Admin_Settings::instance(), 'render_settings_page']; add_menu_page( - __('Open Trust Center', 'opentrust'), - __('Open Trust Center', 'opentrust'), + __('Open Trust Center', 'open-trust-center-by-ettic'), + __('Open Trust Center', 'open-trust-center-by-ettic'), 'manage_options', 'ettic-otc', $settings_page, @@ -64,8 +64,8 @@ public function register_menu(): void { add_submenu_page( 'ettic-otc', - __('Settings', 'opentrust'), - __('Settings', 'opentrust'), + __('Settings', 'open-trust-center-by-ettic'), + __('Settings', 'open-trust-center-by-ettic'), 'manage_options', 'ettic-otc', $settings_page @@ -76,8 +76,8 @@ public function register_menu(): void { if (!empty($settings['ai_enabled'])) { add_submenu_page( 'ettic-otc', - __('Questions', 'opentrust'), - __('Questions', 'opentrust'), + __('Questions', 'open-trust-center-by-ettic'), + __('Questions', 'open-trust-center-by-ettic'), 'manage_options', 'ettic-otc-questions', [Ettic_OTC_Admin_Questions::instance(), 'render_page'] @@ -155,12 +155,12 @@ public function enqueue_assets(string $hook): void { 'ettic-otc-admin', 'window.OpenTrustAdmin = ' . wp_json_encode([ 'i18n' => [ - 'selectBadgeImage' => __('Select Badge Image', 'opentrust'), - 'useAsBadge' => __('Use as Badge', 'opentrust'), - 'selectArtifact' => __('Select Proof Artifact', 'opentrust'), - 'useAsArtifact' => __('Use This File', 'opentrust'), - 'uploadArtifact' => __('Upload File', 'opentrust'), - 'replaceArtifact' => __('Replace File', 'opentrust'), + 'selectBadgeImage' => __('Select Badge Image', 'open-trust-center-by-ettic'), + 'useAsBadge' => __('Use as Badge', 'open-trust-center-by-ettic'), + 'selectArtifact' => __('Select Proof Artifact', 'open-trust-center-by-ettic'), + 'useAsArtifact' => __('Use This File', 'open-trust-center-by-ettic'), + 'uploadArtifact' => __('Upload File', 'open-trust-center-by-ettic'), + 'replaceArtifact' => __('Replace File', 'open-trust-center-by-ettic'), ], ]) . ';', 'before' @@ -175,11 +175,11 @@ public function enqueue_assets(string $hook): void { 'postType' => $screen->post_type, 'catalog' => Ettic_OTC_Catalog::for_js($screen->post_type), 'i18n' => [ - 'noMatchHint' => __('No match in catalog, just keep typing to add manually.', 'opentrust'), - 'helpFact' => __('Auto-filled from catalog, you may want to verify this.', 'opentrust'), - 'helpReview' => __('Auto-filled template, please verify this matches how you use this service.', 'opentrust'), - 'optionHint' => __('click to autofill', 'opentrust'), - 'suggestions' => __('Catalog suggestions', 'opentrust'), + 'noMatchHint' => __('No match in catalog, just keep typing to add manually.', 'open-trust-center-by-ettic'), + 'helpFact' => __('Auto-filled from catalog, you may want to verify this.', 'open-trust-center-by-ettic'), + 'helpReview' => __('Auto-filled template, please verify this matches how you use this service.', 'open-trust-center-by-ettic'), + 'optionHint' => __('click to autofill', 'open-trust-center-by-ettic'), + 'suggestions' => __('Catalog suggestions', 'open-trust-center-by-ettic'), ], ]; wp_add_inline_script( @@ -225,25 +225,25 @@ public function render_plain_permalinks_notice(): void { ?>

- + ' . esc_html__('Settings → Permalinks', 'opentrust') . '' + esc_html__('Your site is using "Plain" permalinks. Please go to %s and choose any other option (Post name is the WordPress default).', 'open-trust-center-by-ettic'), + '' . esc_html__('Settings → Permalinks', 'open-trust-center-by-ettic') . '' ); ?>

- +

- +

- +

  • ?ettic_otc=main
  • @@ -251,8 +251,8 @@ public function render_plain_permalinks_notice(): void {
  • ?ettic_otc=ask

- - + +

diff --git a/includes/class-ettic-otc-chat.php b/includes/class-ettic-otc-chat.php index 82bd1b5..08c3922 100644 --- a/includes/class-ettic-otc-chat.php +++ b/includes/class-ettic-otc-chat.php @@ -109,7 +109,7 @@ public function permission_callback(WP_REST_Request $request): bool|WP_Error { if ($nonce === null || !wp_verify_nonce($nonce, 'wp_rest')) { return new WP_Error( 'rest_forbidden', - __('Invalid nonce — refresh the page and try again.', 'opentrust'), + __('Invalid nonce — refresh the page and try again.', 'open-trust-center-by-ettic'), ['status' => 403] ); } @@ -137,7 +137,7 @@ public function permission_callback(WP_REST_Request $request): bool|WP_Error { if (!$ok) { return new WP_Error( 'ai_turnstile_required', - __('Please complete the anti-abuse challenge and try again.', 'opentrust'), + __('Please complete the anti-abuse challenge and try again.', 'open-trust-center-by-ettic'), ['status' => 403] ); } @@ -149,7 +149,7 @@ public function permission_callback(WP_REST_Request $request): bool|WP_Error { if (empty($ip_check['ok'])) { return new WP_Error( 'ai_rate_limited_ip', - __('You are sending messages too fast. Please wait a moment and try again.', 'opentrust'), + __('You are sending messages too fast. Please wait a moment and try again.', 'open-trust-center-by-ettic'), ['status' => 429, 'retry_after' => $ip_check['retry_after'] ?? 30] ); } @@ -160,7 +160,7 @@ public function permission_callback(WP_REST_Request $request): bool|WP_Error { if (empty($sess_check['ok'])) { return new WP_Error( 'ai_rate_limited_session', - __('You have reached the per-session message limit. Please wait a bit and try again.', 'opentrust'), + __('You have reached the per-session message limit. Please wait a bit and try again.', 'open-trust-center-by-ettic'), ['status' => 429, 'retry_after' => $sess_check['retry_after'] ?? 60] ); } @@ -180,7 +180,7 @@ public function handle_chat(WP_REST_Request $request) { if (empty($settings['ai_enabled']) || empty($settings['ai_provider']) || empty($settings['ai_model'])) { return new WP_Error( 'ai_not_configured', - __('AI chat is not configured on this site.', 'opentrust'), + __('AI chat is not configured on this site.', 'open-trust-center-by-ettic'), ['status' => 503] ); } @@ -189,7 +189,7 @@ public function handle_chat(WP_REST_Request $request) { if (!$adapter) { return new WP_Error( 'ai_bad_provider', - __('Configured provider is unknown.', 'opentrust'), + __('Configured provider is unknown.', 'open-trust-center-by-ettic'), ['status' => 500] ); } @@ -198,7 +198,7 @@ public function handle_chat(WP_REST_Request $request) { if ($api_key === null) { return new WP_Error( 'ai_no_key', - __('No API key stored for the configured provider.', 'opentrust'), + __('No API key stored for the configured provider.', 'open-trust-center-by-ettic'), ['status' => 503] ); } @@ -211,7 +211,7 @@ public function handle_chat(WP_REST_Request $request) { if (empty($messages)) { return new WP_Error( 'ai_empty_messages', - __('Your message is empty.', 'opentrust'), + __('Your message is empty.', 'open-trust-center-by-ettic'), ['status' => 400] ); } @@ -229,7 +229,7 @@ public function handle_chat(WP_REST_Request $request) { if (!Ettic_OTC_Chat_Budget::check_and_reserve($estimated)) { return new WP_Error( 'budget_exhausted', - __('The daily chat budget for this site has been reached. Please try again later.', 'opentrust'), + __('The daily chat budget for this site has been reached. Please try again later.', 'open-trust-center-by-ettic'), [ 'status' => 503, 'reset_at' => gmdate('c', Ettic_OTC_Chat_Budget::daily_reset_at()), @@ -391,7 +391,7 @@ private function drive_stream(Ettic_OTC_Chat_Provider $adapter, array $args): ar $exception = $this->run_chat($adapter, $args, $on_chunk); if ($exception !== null) { self::send_sse('error', [ - 'message' => __('Chat provider failed unexpectedly.', 'opentrust'), + 'message' => __('Chat provider failed unexpectedly.', 'open-trust-center-by-ettic'), 'detail' => $exception->getMessage(), ]); } @@ -719,7 +719,7 @@ public static function resolve_tool(string $name, array $args, array $corpus, ar if (isset($seen_calls[$signature])) { return [self::error_search_result(sprintf( /* translators: %s is the tool name (get_document or search_documents). */ - __('You already called %s with the same arguments earlier in this conversation. Pick a different document id from the index, or rephrase the search query with different keywords.', 'opentrust'), + __('You already called %s with the same arguments earlier in this conversation. Pick a different document id from the index, or rephrase the search query with different keywords.', 'open-trust-center-by-ettic'), $name ))]; } @@ -729,7 +729,7 @@ public static function resolve_tool(string $name, array $args, array $corpus, ar case 'get_document': $id = trim((string) ($args['id'] ?? '')); if ($id === '') { - return [self::error_search_result(__('Document id is required.', 'opentrust'))]; + return [self::error_search_result(__('Document id is required.', 'open-trust-center-by-ettic'))]; } foreach ($documents as $doc) { if ((string) ($doc['id'] ?? '') === $id) { @@ -738,7 +738,7 @@ public static function resolve_tool(string $name, array $args, array $corpus, ar } return [self::error_search_result(sprintf( /* translators: %s is the requested document id. */ - __('No document with id "%s". Pick one of the ids listed in the corpus index above.', 'opentrust'), + __('No document with id "%s". Pick one of the ids listed in the corpus index above.', 'open-trust-center-by-ettic'), $id ))]; @@ -746,16 +746,16 @@ public static function resolve_tool(string $name, array $args, array $corpus, ar $query = trim((string) ($args['query'] ?? '')); $limit = max(1, min(10, (int) ($args['limit'] ?? 5))); if ($query === '') { - return [self::error_search_result(__('Search query is empty.', 'opentrust'))]; + return [self::error_search_result(__('Search query is empty.', 'open-trust-center-by-ettic'))]; } if ($bm25 === null) { - return [self::error_search_result(__('Search index unavailable.', 'opentrust'))]; + return [self::error_search_result(__('Search index unavailable.', 'open-trust-center-by-ettic'))]; } $hits = Ettic_OTC_Chat_Search::search($bm25, $query, $limit); if (empty($hits)) { return [self::error_search_result(sprintf( /* translators: %s is the search query. */ - __('No documents matched "%s". Try broader keywords or pick a document id from the corpus index above.', 'opentrust'), + __('No documents matched "%s". Try broader keywords or pick a document id from the corpus index above.', 'open-trust-center-by-ettic'), $query ))]; } @@ -767,12 +767,12 @@ public static function resolve_tool(string $name, array $args, array $corpus, ar } return $results !== [] ? $results - : [self::error_search_result(__('Search ranking returned no usable results.', 'opentrust'))]; + : [self::error_search_result(__('Search ranking returned no usable results.', 'open-trust-center-by-ettic'))]; } return [self::error_search_result(sprintf( /* translators: %s is the unknown tool name. */ - __('Unknown tool: %s', 'opentrust'), + __('Unknown tool: %s', 'open-trust-center-by-ettic'), $name ))]; } diff --git a/includes/class-ettic-otc-cpt.php b/includes/class-ettic-otc-cpt.php index 1e4ae91..e37ebb3 100644 --- a/includes/class-ettic-otc-cpt.php +++ b/includes/class-ettic-otc-cpt.php @@ -214,13 +214,13 @@ static function (string $new, string $old, \WP_Post $post) use ($cpts, $callback */ public function filter_enter_title_here(string $text, \WP_Post $post): string { if ($post->post_type === self::SUBPROCESSOR) { - return __('Pick from the catalog or type your own subprocessor name', 'opentrust'); + return __('Pick from the catalog or type your own subprocessor name', 'open-trust-center-by-ettic'); } if ($post->post_type === self::DATA_PRACTICE) { - return __('Pick from the catalog or type your own, e.g. Analytics or Transactional Email', 'opentrust'); + return __('Pick from the catalog or type your own, e.g. Analytics or Transactional Email', 'open-trust-center-by-ettic'); } if ($post->post_type === self::CERTIFICATION) { - return __('Pick from the catalog or type your own, e.g. SOC 2 Type II or ISO 27001', 'opentrust'); + return __('Pick from the catalog or type your own, e.g. SOC 2 Type II or ISO 27001', 'open-trust-center-by-ettic'); } return $text; } @@ -233,17 +233,17 @@ public static function register_post_types(): void { // ── Policies ── register_post_type(self::POLICY, [ 'labels' => [ - 'name' => __('Policies', 'opentrust'), - 'singular_name' => __('Policy', 'opentrust'), - 'add_new' => __('Add Policy', 'opentrust'), - 'add_new_item' => __('Add New Policy', 'opentrust'), - 'edit_item' => __('Edit Policy', 'opentrust'), - 'new_item' => __('New Policy', 'opentrust'), - 'view_item' => __('View Policy', 'opentrust'), - 'search_items' => __('Search Policies', 'opentrust'), - 'not_found' => __('No policies found.', 'opentrust'), - 'not_found_in_trash' => __('No policies in trash.', 'opentrust'), - 'all_items' => __('Policies', 'opentrust'), + 'name' => __('Policies', 'open-trust-center-by-ettic'), + 'singular_name' => __('Policy', 'open-trust-center-by-ettic'), + 'add_new' => __('Add Policy', 'open-trust-center-by-ettic'), + 'add_new_item' => __('Add New Policy', 'open-trust-center-by-ettic'), + 'edit_item' => __('Edit Policy', 'open-trust-center-by-ettic'), + 'new_item' => __('New Policy', 'open-trust-center-by-ettic'), + 'view_item' => __('View Policy', 'open-trust-center-by-ettic'), + 'search_items' => __('Search Policies', 'open-trust-center-by-ettic'), + 'not_found' => __('No policies found.', 'open-trust-center-by-ettic'), + 'not_found_in_trash' => __('No policies in trash.', 'open-trust-center-by-ettic'), + 'all_items' => __('Policies', 'open-trust-center-by-ettic'), ], // public=>true is required so WPML and Polylang detect the post type // as translatable content and offer per-language variants in their UIs. @@ -267,16 +267,16 @@ public static function register_post_types(): void { // ── Certifications ── register_post_type(self::CERTIFICATION, [ 'labels' => [ - 'name' => __('Certifications', 'opentrust'), - 'singular_name' => __('Certification', 'opentrust'), - 'add_new' => __('Add Certification', 'opentrust'), - 'add_new_item' => __('Add New Certification', 'opentrust'), - 'edit_item' => __('Edit Certification', 'opentrust'), - 'new_item' => __('New Certification', 'opentrust'), - 'search_items' => __('Search Certifications', 'opentrust'), - 'not_found' => __('No certifications found.', 'opentrust'), - 'not_found_in_trash' => __('No certifications in trash.', 'opentrust'), - 'all_items' => __('Certifications', 'opentrust'), + 'name' => __('Certifications', 'open-trust-center-by-ettic'), + 'singular_name' => __('Certification', 'open-trust-center-by-ettic'), + 'add_new' => __('Add Certification', 'open-trust-center-by-ettic'), + 'add_new_item' => __('Add New Certification', 'open-trust-center-by-ettic'), + 'edit_item' => __('Edit Certification', 'open-trust-center-by-ettic'), + 'new_item' => __('New Certification', 'open-trust-center-by-ettic'), + 'search_items' => __('Search Certifications', 'open-trust-center-by-ettic'), + 'not_found' => __('No certifications found.', 'open-trust-center-by-ettic'), + 'not_found_in_trash' => __('No certifications in trash.', 'open-trust-center-by-ettic'), + 'all_items' => __('Certifications', 'open-trust-center-by-ettic'), ], // public=>true is required so WPML and Polylang detect the post type // as translatable content and offer per-language variants in their UIs. @@ -300,16 +300,16 @@ public static function register_post_types(): void { // ── Subprocessors ── register_post_type(self::SUBPROCESSOR, [ 'labels' => [ - 'name' => __('Subprocessors', 'opentrust'), - 'singular_name' => __('Subprocessor', 'opentrust'), - 'add_new' => __('Add Subprocessor', 'opentrust'), - 'add_new_item' => __('Add New Subprocessor', 'opentrust'), - 'edit_item' => __('Edit Subprocessor', 'opentrust'), - 'new_item' => __('New Subprocessor', 'opentrust'), - 'search_items' => __('Search Subprocessors', 'opentrust'), - 'not_found' => __('No subprocessors found.', 'opentrust'), - 'not_found_in_trash' => __('No subprocessors in trash.', 'opentrust'), - 'all_items' => __('Subprocessors', 'opentrust'), + 'name' => __('Subprocessors', 'open-trust-center-by-ettic'), + 'singular_name' => __('Subprocessor', 'open-trust-center-by-ettic'), + 'add_new' => __('Add Subprocessor', 'open-trust-center-by-ettic'), + 'add_new_item' => __('Add New Subprocessor', 'open-trust-center-by-ettic'), + 'edit_item' => __('Edit Subprocessor', 'open-trust-center-by-ettic'), + 'new_item' => __('New Subprocessor', 'open-trust-center-by-ettic'), + 'search_items' => __('Search Subprocessors', 'open-trust-center-by-ettic'), + 'not_found' => __('No subprocessors found.', 'open-trust-center-by-ettic'), + 'not_found_in_trash' => __('No subprocessors in trash.', 'open-trust-center-by-ettic'), + 'all_items' => __('Subprocessors', 'open-trust-center-by-ettic'), ], // public=>true is required so WPML and Polylang detect the post type // as translatable content and offer per-language variants in their UIs. @@ -333,16 +333,16 @@ public static function register_post_types(): void { // ── Data Practices ── register_post_type(self::DATA_PRACTICE, [ 'labels' => [ - 'name' => __('Data Practices', 'opentrust'), - 'singular_name' => __('Data Practice', 'opentrust'), - 'add_new' => __('Add Data Practice', 'opentrust'), - 'add_new_item' => __('Add New Data Practice', 'opentrust'), - 'edit_item' => __('Edit Data Practice', 'opentrust'), - 'new_item' => __('New Data Practice', 'opentrust'), - 'search_items' => __('Search Data Practices', 'opentrust'), - 'not_found' => __('No data practices found.', 'opentrust'), - 'not_found_in_trash' => __('No data practices in trash.', 'opentrust'), - 'all_items' => __('Data Practices', 'opentrust'), + 'name' => __('Data Practices', 'open-trust-center-by-ettic'), + 'singular_name' => __('Data Practice', 'open-trust-center-by-ettic'), + 'add_new' => __('Add Data Practice', 'open-trust-center-by-ettic'), + 'add_new_item' => __('Add New Data Practice', 'open-trust-center-by-ettic'), + 'edit_item' => __('Edit Data Practice', 'open-trust-center-by-ettic'), + 'new_item' => __('New Data Practice', 'open-trust-center-by-ettic'), + 'search_items' => __('Search Data Practices', 'open-trust-center-by-ettic'), + 'not_found' => __('No data practices found.', 'open-trust-center-by-ettic'), + 'not_found_in_trash' => __('No data practices in trash.', 'open-trust-center-by-ettic'), + 'all_items' => __('Data Practices', 'open-trust-center-by-ettic'), ], // public=>true is required so WPML and Polylang detect the post type // as translatable content and offer per-language variants in their UIs. @@ -366,17 +366,17 @@ public static function register_post_types(): void { // ── FAQs ── register_post_type(self::FAQ, [ 'labels' => [ - 'name' => __('FAQs', 'opentrust'), - 'singular_name' => __('FAQ', 'opentrust'), - 'add_new' => __('Add FAQ', 'opentrust'), - 'add_new_item' => __('Add New FAQ', 'opentrust'), - 'edit_item' => __('Edit FAQ', 'opentrust'), - 'new_item' => __('New FAQ', 'opentrust'), - 'view_item' => __('View FAQ', 'opentrust'), - 'search_items' => __('Search FAQs', 'opentrust'), - 'not_found' => __('No FAQs found.', 'opentrust'), - 'not_found_in_trash' => __('No FAQs in trash.', 'opentrust'), - 'all_items' => __('FAQs', 'opentrust'), + 'name' => __('FAQs', 'open-trust-center-by-ettic'), + 'singular_name' => __('FAQ', 'open-trust-center-by-ettic'), + 'add_new' => __('Add FAQ', 'open-trust-center-by-ettic'), + 'add_new_item' => __('Add New FAQ', 'open-trust-center-by-ettic'), + 'edit_item' => __('Edit FAQ', 'open-trust-center-by-ettic'), + 'new_item' => __('New FAQ', 'open-trust-center-by-ettic'), + 'view_item' => __('View FAQ', 'open-trust-center-by-ettic'), + 'search_items' => __('Search FAQs', 'open-trust-center-by-ettic'), + 'not_found' => __('No FAQs found.', 'open-trust-center-by-ettic'), + 'not_found_in_trash' => __('No FAQs in trash.', 'open-trust-center-by-ettic'), + 'all_items' => __('FAQs', 'open-trust-center-by-ettic'), ], 'public' => true, 'publicly_queryable' => false, @@ -398,11 +398,11 @@ public static function register_post_types(): void { // ────────────────────────────────────────────── public function add_meta_boxes(): void { - add_meta_box('ettic_otc_cert_details', __('Certification Details', 'opentrust'), [$this, 'render_cert_meta_box'], self::CERTIFICATION, 'normal', 'high'); - add_meta_box('ettic_otc_policy_details', __('Policy Details', 'opentrust'), [$this, 'render_policy_meta_box'], self::POLICY, 'side', 'high'); - add_meta_box('ettic_otc_sub_details', __('Subprocessor Details', 'opentrust'), [$this, 'render_sub_meta_box'], self::SUBPROCESSOR, 'normal', 'high'); - add_meta_box('ettic_otc_dp_details', __('Data Practice Details', 'opentrust'), [$this, 'render_dp_meta_box'], self::DATA_PRACTICE, 'normal', 'high'); - add_meta_box('ettic_otc_faq_details', __('FAQ Details', 'opentrust'), [$this, 'render_faq_meta_box'], self::FAQ, 'side', 'high'); + add_meta_box('ettic_otc_cert_details', __('Certification Details', 'open-trust-center-by-ettic'), [$this, 'render_cert_meta_box'], self::CERTIFICATION, 'normal', 'high'); + add_meta_box('ettic_otc_policy_details', __('Policy Details', 'open-trust-center-by-ettic'), [$this, 'render_policy_meta_box'], self::POLICY, 'side', 'high'); + add_meta_box('ettic_otc_sub_details', __('Subprocessor Details', 'open-trust-center-by-ettic'), [$this, 'render_sub_meta_box'], self::SUBPROCESSOR, 'normal', 'high'); + add_meta_box('ettic_otc_dp_details', __('Data Practice Details', 'open-trust-center-by-ettic'), [$this, 'render_dp_meta_box'], self::DATA_PRACTICE, 'normal', 'high'); + add_meta_box('ettic_otc_faq_details', __('FAQ Details', 'open-trust-center-by-ettic'), [$this, 'render_faq_meta_box'], self::FAQ, 'side', 'high'); } // ── Certification meta box ── @@ -423,76 +423,76 @@ public function render_cert_meta_box(\WP_Post $post): void { $artifact_name = $artifact_id ? get_the_title($artifact_id) : ''; $types = [ - 'certified' => __('Audited certification (issued by a third party)', 'opentrust'), - 'compliant' => __('Self-attested alignment (no external audit)', 'opentrust'), + 'certified' => __('Audited certification (issued by a third party)', 'open-trust-center-by-ettic'), + 'compliant' => __('Self-attested alignment (no external audit)', 'open-trust-center-by-ettic'), ]; $statuses = [ - 'active' => __('Active / currently met', 'opentrust'), - 'in_progress' => __('In progress', 'opentrust'), - 'expired' => __('Expired / lapsed', 'opentrust'), + 'active' => __('Active / currently met', 'open-trust-center-by-ettic'), + 'in_progress' => __('In progress', 'open-trust-center-by-ettic'), + 'expired' => __('Expired / lapsed', 'open-trust-center-by-ettic'), ]; ?>
- + -

+

- + -

+

- - + +
- +
- +
- + - - -

+ + +

- +
- +
- - -

+ + +

- - -

+ + +

+ printf(esc_html__('Version %s', 'open-trust-center-by-ettic'), esc_html((string) $version)); ?>

- +

@@ -559,12 +559,12 @@ public function render_policy_meta_box(\WP_Post $post): void {
- - -

+ + +

- +
- +
- +
$ot_citation): $ot_citation_name = is_array($ot_citation) ? ($ot_citation['name'] ?? '') : (string) $ot_citation; @@ -616,30 +616,30 @@ public function render_policy_meta_box(\WP_Post $post): void { - + - +
-

+

- +
- +
- - -

+ + +

- + -

+

ID, '_ettic_otc_sub_dpa_signed', true); ?>
- + -

+

- + -

+

- - + +
- +
-

+

- +
$item): ?> - + - +
- +
- +
- - + +
- +
$entry): ?> - + - +
- +
-

+

- + -

+

- + -

+

- - + +

open($tmp, \ZipArchive::OVERWRITE | \ZipArchive::CREATE) !== true) { - throw new \RuntimeException(esc_html__('Could not open ZIP for writing.', 'opentrust')); + throw new \RuntimeException(esc_html__('Could not open ZIP for writing.', 'open-trust-center-by-ettic')); } $zip->addFromString('manifest.json', wp_json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); @@ -237,13 +237,13 @@ public static function validate_manifest(array $manifest): array { $format = (string) ($manifest['format'] ?? ''); if (!in_array($format, [self::FORMAT_SETTINGS, self::FORMAT_CONTENT], true)) { - $errors[] = __('Unrecognised export format.', 'opentrust'); + $errors[] = __('Unrecognised export format.', 'open-trust-center-by-ettic'); } if ((int) ($manifest['schema'] ?? 0) !== self::SCHEMA_VERSION) { $errors[] = sprintf( /* translators: %1$d: schema version found, %2$d: schema version expected */ - __('Schema version mismatch (found %1$d, expected %2$d).', 'opentrust'), + __('Schema version mismatch (found %1$d, expected %2$d).', 'open-trust-center-by-ettic'), (int) ($manifest['schema'] ?? 0), self::SCHEMA_VERSION ); @@ -254,7 +254,7 @@ public static function validate_manifest(array $manifest): array { if ($their_major !== $our_major) { $errors[] = sprintf( /* translators: %1$s: their version, %2$s: our version */ - __('Plugin major version mismatch (export: %1$s, this site: %2$s).', 'opentrust'), + __('Plugin major version mismatch (export: %1$s, this site: %2$s).', 'open-trust-center-by-ettic'), (string) ($manifest['ettic_otc_version'] ?? '?'), ETTIC_OTC_VERSION ); @@ -393,20 +393,20 @@ public static function apply_settings_import(array $manifest, string $zip_path): public static function read_zip(string $zip_path): array { if (!class_exists('ZipArchive')) { - throw new \RuntimeException(esc_html__('PHP ZipArchive extension is required.', 'opentrust')); + throw new \RuntimeException(esc_html__('PHP ZipArchive extension is required.', 'open-trust-center-by-ettic')); } $zip = new \ZipArchive(); if ($zip->open($zip_path) !== true) { - throw new \RuntimeException(esc_html__('Could not open uploaded archive.', 'opentrust')); + throw new \RuntimeException(esc_html__('Could not open uploaded archive.', 'open-trust-center-by-ettic')); } $raw = $zip->getFromName('manifest.json'); $zip->close(); if ($raw === false) { - throw new \RuntimeException(esc_html__('Archive is missing manifest.json.', 'opentrust')); + throw new \RuntimeException(esc_html__('Archive is missing manifest.json.', 'open-trust-center-by-ettic')); } $manifest = json_decode($raw, true); if (!is_array($manifest)) { - throw new \RuntimeException(esc_html__('manifest.json could not be parsed.', 'opentrust')); + throw new \RuntimeException(esc_html__('manifest.json could not be parsed.', 'open-trust-center-by-ettic')); } return ['manifest' => $manifest, 'zip_path' => $zip_path]; } @@ -689,7 +689,7 @@ private static function sideload_bundled_media(array $media, string $zip_path, a $map = []; $zip = new \ZipArchive(); if ($zip->open($zip_path) !== true) { - $errors[] = __('Could not reopen archive for media import.', 'opentrust'); + $errors[] = __('Could not reopen archive for media import.', 'open-trust-center-by-ettic'); return []; } @@ -704,7 +704,7 @@ private static function sideload_bundled_media(array $media, string $zip_path, a if ($contents === false) { $errors[] = sprintf( /* translators: %s: media path */ - __('Bundled media missing during import: %s', 'opentrust'), + __('Bundled media missing during import: %s', 'open-trust-center-by-ettic'), (string) $entry['path'] ); continue; @@ -724,7 +724,7 @@ private static function sideload_bundled_media(array $media, string $zip_path, a if (file_put_contents($dest_path, $contents) === false) { $errors[] = sprintf( /* translators: %s: filename */ - __('Could not write attachment file: %s', 'opentrust'), + __('Could not write attachment file: %s', 'open-trust-center-by-ettic'), $filename ); continue; @@ -742,7 +742,7 @@ private static function sideload_bundled_media(array $media, string $zip_path, a continue; } if (!$att_id) { - $errors[] = __('Could not create attachment.', 'opentrust'); + $errors[] = __('Could not create attachment.', 'open-trust-center-by-ettic'); wp_delete_file($dest_path); continue; } diff --git a/includes/class-ettic-otc-render.php b/includes/class-ettic-otc-render.php index 393a726..28b9dfe 100644 --- a/includes/class-ettic-otc-render.php +++ b/includes/class-ettic-otc-render.php @@ -80,13 +80,13 @@ private function render_chat_page(): void { private function handle_chat_noscript_post(array $settings): array { $nonce = isset($_POST['_wpnonce']) ? sanitize_text_field((string) wp_unslash($_POST['_wpnonce'])) : ''; if (!wp_verify_nonce($nonce, 'ettic_otc_chat_noscript')) { - return ['error' => __('Session expired. Please reload the page and try again.', 'opentrust')]; + return ['error' => __('Session expired. Please reload the page and try again.', 'open-trust-center-by-ettic')]; } $question = isset($_POST['question']) ? sanitize_textarea_field((string) wp_unslash($_POST['question'])) : ''; $max_len = (int) ($settings['ai_max_message_length'] ?? Ettic_OTC_Chat::DEFAULT_MAX_MESSAGE_LENGTH); if ($question === '') { - return ['error' => __('Please enter a question.', 'opentrust')]; + return ['error' => __('Please enter a question.', 'open-trust-center-by-ettic')]; } if (strlen($question) > $max_len) { $question = substr($question, 0, $max_len); @@ -95,7 +95,7 @@ private function handle_chat_noscript_post(array $settings): array { $adapter = Ettic_OTC_Chat_Provider::for((string) $settings['ai_provider']); $api_key = Ettic_OTC_Chat_Secrets::get((string) $settings['ai_provider']); if (!$adapter || $api_key === null) { - return ['error' => __('AI chat is not configured.', 'opentrust')]; + return ['error' => __('AI chat is not configured.', 'open-trust-center-by-ettic')]; } $locale = (string) determine_locale(); @@ -267,8 +267,8 @@ private function render_404(): void { echo 'Not Found'; echo ''; echo '

404

'; - echo '

' . esc_html__('Page not found.', 'opentrust') . '

'; - echo '' . esc_html__('Back to Trust Center', 'opentrust') . ''; + echo '

' . esc_html__('Page not found.', 'open-trust-center-by-ettic') . '

'; + echo '' . esc_html__('Back to Trust Center', 'open-trust-center-by-ettic') . ''; echo '
'; } @@ -439,32 +439,32 @@ public static function updated_pill(string $section_key, array $data): void { $diff = time() - (int) $timestamp; if ($diff < 60) { - $text = __('Updated just now', 'opentrust'); + $text = __('Updated just now', 'open-trust-center-by-ettic'); } elseif ($diff < 3600) { $minutes = (int) floor($diff / 60); $text = sprintf( /* translators: %d: number of minutes since last update */ - _n('Updated %d minute ago', 'Updated %d minutes ago', $minutes, 'opentrust'), + _n('Updated %d minute ago', 'Updated %d minutes ago', $minutes, 'open-trust-center-by-ettic'), $minutes ); } elseif ($diff < 86400) { $hours = (int) floor($diff / 3600); $text = sprintf( /* translators: %d: number of hours since last update */ - _n('Updated %d hour ago', 'Updated %d hours ago', $hours, 'opentrust'), + _n('Updated %d hour ago', 'Updated %d hours ago', $hours, 'open-trust-center-by-ettic'), $hours ); } elseif ($diff < 2592000) { $days = (int) floor($diff / 86400); $text = sprintf( /* translators: %d: number of days since last update */ - _n('Updated %d day ago', 'Updated %d days ago', $days, 'opentrust'), + _n('Updated %d day ago', 'Updated %d days ago', $days, 'open-trust-center-by-ettic'), $days ); } else { $text = sprintf( /* translators: %s = formatted date */ - __('Updated %s', 'opentrust'), + __('Updated %s', 'open-trust-center-by-ettic'), wp_date('M j, Y', (int) $timestamp) ); } @@ -508,11 +508,11 @@ private function get_policy_meta(int $post_id): array { */ public static function policy_category_labels(): array { return [ - 'security' => __('Security', 'opentrust'), - 'privacy' => __('Privacy', 'opentrust'), - 'compliance' => __('Compliance', 'opentrust'), - 'operational' => __('Operational', 'opentrust'), - 'other' => __('General', 'opentrust'), + 'security' => __('Security', 'open-trust-center-by-ettic'), + 'privacy' => __('Privacy', 'open-trust-center-by-ettic'), + 'compliance' => __('Compliance', 'open-trust-center-by-ettic'), + 'operational' => __('Operational', 'open-trust-center-by-ettic'), + 'other' => __('General', 'open-trust-center-by-ettic'), ]; } @@ -523,9 +523,9 @@ public static function policy_category_labels(): array { */ public static function cert_status_labels(): array { return [ - 'active' => __('Certified', 'opentrust'), - 'in_progress' => __('In audit', 'opentrust'), - 'expired' => __('Expired', 'opentrust'), + 'active' => __('Certified', 'open-trust-center-by-ettic'), + 'in_progress' => __('In audit', 'open-trust-center-by-ettic'), + 'expired' => __('Expired', 'open-trust-center-by-ettic'), ]; } @@ -534,20 +534,20 @@ public static function cert_status_labels(): array { */ public static function cert_aligned_status_labels(): array { return [ - 'active' => __('Compliant', 'opentrust'), - 'in_progress' => __('Working toward', 'opentrust'), - 'expired' => __('Lapsed', 'opentrust'), + 'active' => __('Compliant', 'open-trust-center-by-ettic'), + 'in_progress' => __('Working toward', 'open-trust-center-by-ettic'), + 'expired' => __('Lapsed', 'open-trust-center-by-ettic'), ]; } public static function legal_basis_labels(): array { return [ - 'consent' => __('Consent', 'opentrust'), - 'contract' => __('Contractual Necessity', 'opentrust'), - 'legitimate_interest' => __('Legitimate Interest', 'opentrust'), - 'legal_obligation' => __('Legal Obligation', 'opentrust'), - 'vital_interest' => __('Vital Interest', 'opentrust'), - 'public_interest' => __('Public Interest', 'opentrust'), + 'consent' => __('Consent', 'open-trust-center-by-ettic'), + 'contract' => __('Contractual Necessity', 'open-trust-center-by-ettic'), + 'legitimate_interest' => __('Legitimate Interest', 'open-trust-center-by-ettic'), + 'legal_obligation' => __('Legal Obligation', 'open-trust-center-by-ettic'), + 'vital_interest' => __('Vital Interest', 'open-trust-center-by-ettic'), + 'public_interest' => __('Public Interest', 'open-trust-center-by-ettic'), ]; } diff --git a/includes/class-ettic-otc-version.php b/includes/class-ettic-otc-version.php index 8bad52c..2384406 100644 --- a/includes/class-ettic-otc-version.php +++ b/includes/class-ettic-otc-version.php @@ -124,7 +124,7 @@ public static function ensure_initial_version(int $post_id): void { public function add_version_history_meta_box(): void { add_meta_box( 'ettic_otc_version_history', - __('Version History', 'opentrust'), + __('Version History', 'open-trust-center-by-ettic'), [$this, 'render_version_history'], Ettic_OTC_CPT::POLICY, 'side', @@ -146,10 +146,10 @@ public function render_version_history(\WP_Post $post): void { if (empty($revisions)) { printf( '

%s v%d

', - esc_html__('Current version:', 'opentrust'), + esc_html__('Current version:', 'open-trust-center-by-ettic'), (int) $current_version ); - echo '

' . esc_html__('Version history will appear after the first update.', 'opentrust') . '

'; + echo '

' . esc_html__('Version history will appear after the first update.', 'open-trust-center-by-ettic') . '

'; return; } ?> @@ -157,16 +157,16 @@ public function render_version_history(\WP_Post $post): void {
created_at . ' UTC'))); ?> refused): ?> - + question); ?>
- - - + + + - + ID, '_ettic_otc_version', true); @@ -180,12 +180,12 @@ public function render_version_history(\WP_Post $post): void { diff --git a/includes/data/faq-catalog.php b/includes/data/faq-catalog.php index 2240146..5d065a0 100644 --- a/includes/data/faq-catalog.php +++ b/includes/data/faq-catalog.php @@ -26,52 +26,52 @@ return [ 'what-is-a-trust-center' => [ - 'question' => __( 'What is a trust center?', 'opentrust' ), - 'answer' => __( 'A trust center is a public page where a company shares information about how it handles security, privacy, and compliance. It usually includes security policies, a list of subprocessors, compliance certifications, and details about how customer data is handled. The goal is to give customers, partners, and prospects one place to answer due diligence questions without having to email anyone.', 'opentrust' ), + 'question' => __( 'What is a trust center?', 'open-trust-center-by-ettic' ), + 'answer' => __( 'A trust center is a public page where a company shares information about how it handles security, privacy, and compliance. It usually includes security policies, a list of subprocessors, compliance certifications, and details about how customer data is handled. The goal is to give customers, partners, and prospects one place to answer due diligence questions without having to email anyone.', 'open-trust-center-by-ettic' ), ], 'what-is-a-dpa' => [ - 'question' => __( 'What is a Data Processing Agreement (DPA)?', 'opentrust' ), - 'answer' => __( 'A Data Processing Agreement, or DPA, is a contract between a company that collects personal data and a company that processes that data on its behalf. It defines what data can be processed, for what purpose, how long it can be kept, and what security measures must be in place. Under privacy laws like the GDPR, a DPA is required whenever one company processes personal data for another.', 'opentrust' ), + 'question' => __( 'What is a Data Processing Agreement (DPA)?', 'open-trust-center-by-ettic' ), + 'answer' => __( 'A Data Processing Agreement, or DPA, is a contract between a company that collects personal data and a company that processes that data on its behalf. It defines what data can be processed, for what purpose, how long it can be kept, and what security measures must be in place. Under privacy laws like the GDPR, a DPA is required whenever one company processes personal data for another.', 'open-trust-center-by-ettic' ), ], 'what-is-a-subprocessor' => [ - 'question' => __( 'What is a subprocessor?', 'opentrust' ), - 'answer' => __( 'A subprocessor is a third-party service that a company uses to help deliver its product, and that may come into contact with customer data along the way. Common examples include cloud hosting providers, email delivery services, analytics platforms, and customer support tools. Companies publish subprocessor lists so customers can see exactly which vendors may handle their data.', 'opentrust' ), + 'question' => __( 'What is a subprocessor?', 'open-trust-center-by-ettic' ), + 'answer' => __( 'A subprocessor is a third-party service that a company uses to help deliver its product, and that may come into contact with customer data along the way. Common examples include cloud hosting providers, email delivery services, analytics platforms, and customer support tools. Companies publish subprocessor lists so customers can see exactly which vendors may handle their data.', 'open-trust-center-by-ettic' ), ], 'controller-vs-processor' => [ - 'question' => __( 'What is the difference between a data controller and a data processor?', 'opentrust' ), - 'answer' => __( "The data controller is the party that decides why and how personal data is collected and used. The data processor is the party that handles that data on the controller's behalf, following the controller's instructions. A SaaS customer is usually the controller of their end-user data, while the SaaS vendor acts as the processor. Each role carries different legal responsibilities under privacy laws like the GDPR.", 'opentrust' ), + 'question' => __( 'What is the difference between a data controller and a data processor?', 'open-trust-center-by-ettic' ), + 'answer' => __( "The data controller is the party that decides why and how personal data is collected and used. The data processor is the party that handles that data on the controller's behalf, following the controller's instructions. A SaaS customer is usually the controller of their end-user data, while the SaaS vendor acts as the processor. Each role carries different legal responsibilities under privacy laws like the GDPR.", 'open-trust-center-by-ettic' ), ], 'what-is-personal-data' => [ - 'question' => __( 'What is personal data?', 'opentrust' ), - 'answer' => __( 'Personal data is any information that can be used to identify a living person, either on its own or when combined with other information. Obvious examples include names, email addresses, phone numbers, and home addresses. Less obvious examples include IP addresses, device identifiers, cookies, and location data. Privacy laws such as the GDPR and CCPA treat personal data as something that must be collected, stored, and shared with care.', 'opentrust' ), + 'question' => __( 'What is personal data?', 'open-trust-center-by-ettic' ), + 'answer' => __( 'Personal data is any information that can be used to identify a living person, either on its own or when combined with other information. Obvious examples include names, email addresses, phone numbers, and home addresses. Less obvious examples include IP addresses, device identifiers, cookies, and location data. Privacy laws such as the GDPR and CCPA treat personal data as something that must be collected, stored, and shared with care.', 'open-trust-center-by-ettic' ), ], 'what-is-responsible-disclosure' => [ - 'question' => __( 'What is responsible disclosure?', 'opentrust' ), - 'answer' => __( 'Responsible disclosure is the practice of reporting a security vulnerability privately to the company that owns the affected system, giving them a reasonable amount of time to fix it before any details are shared publicly. It protects users from being exposed to a known issue before a patch is available. Most trust centers include a contact address or form for reporting vulnerabilities this way.', 'opentrust' ), + 'question' => __( 'What is responsible disclosure?', 'open-trust-center-by-ettic' ), + 'answer' => __( 'Responsible disclosure is the practice of reporting a security vulnerability privately to the company that owns the affected system, giving them a reasonable amount of time to fix it before any details are shared publicly. It protects users from being exposed to a known issue before a patch is available. Most trust centers include a contact address or form for reporting vulnerabilities this way.', 'open-trust-center-by-ettic' ), ], 'what-is-a-compliance-certification' => [ - 'question' => __( 'What is a compliance certification?', 'opentrust' ), - 'answer' => __( "A compliance certification is a formal statement, usually issued by an independent auditor, confirming that a company meets the requirements of a specific security or privacy standard. Certifications give customers a way to trust a company's practices without having to inspect them directly. The scope, issuing body, and validity period are typically listed alongside each certification in a trust center.", 'opentrust' ), + 'question' => __( 'What is a compliance certification?', 'open-trust-center-by-ettic' ), + 'answer' => __( "A compliance certification is a formal statement, usually issued by an independent auditor, confirming that a company meets the requirements of a specific security or privacy standard. Certifications give customers a way to trust a company's practices without having to inspect them directly. The scope, issuing body, and validity period are typically listed alongside each certification in a trust center.", 'open-trust-center-by-ettic' ), ], 'what-is-a-security-policy' => [ - 'question' => __( 'What is a security policy?', 'opentrust' ), - 'answer' => __( 'A security policy is a written document that describes how a company protects its systems, data, and people. Policies commonly cover topics like access control, incident response, acceptable use, vendor management, and business continuity. Publishing policies in a trust center lets customers see how security is handled without needing to sign an NDA first.', 'opentrust' ), + 'question' => __( 'What is a security policy?', 'open-trust-center-by-ettic' ), + 'answer' => __( 'A security policy is a written document that describes how a company protects its systems, data, and people. Policies commonly cover topics like access control, incident response, acceptable use, vendor management, and business continuity. Publishing policies in a trust center lets customers see how security is handled without needing to sign an NDA first.', 'open-trust-center-by-ettic' ), ], 'why-publish-subprocessors' => [ - 'question' => __( 'Why do companies publish a list of subprocessors?', 'opentrust' ), - 'answer' => __( 'Publishing a subprocessor list is a transparency practice, and in many cases a legal requirement, that lets customers see every third party that may handle their data. It gives customers the chance to review new vendors before they start processing data, and it makes it easier to meet their own compliance obligations. Most trust centers also offer a way to be notified when the list changes.', 'opentrust' ), + 'question' => __( 'Why do companies publish a list of subprocessors?', 'open-trust-center-by-ettic' ), + 'answer' => __( 'Publishing a subprocessor list is a transparency practice, and in many cases a legal requirement, that lets customers see every third party that may handle their data. It gives customers the chance to review new vendors before they start processing data, and it makes it easier to meet their own compliance obligations. Most trust centers also offer a way to be notified when the list changes.', 'open-trust-center-by-ettic' ), ], 'what-is-a-data-practice' => [ - 'question' => __( 'What is a data practice?', 'opentrust' ), - 'answer' => __( 'A data practice describes a specific way a company collects, uses, stores, or shares information. Each practice usually spells out what data is involved, why it is collected, how long it is kept, and who it is shared with. Grouping data practices by category, such as account data, usage data, or support data, helps customers understand exactly what happens to their information.', 'opentrust' ), + 'question' => __( 'What is a data practice?', 'open-trust-center-by-ettic' ), + 'answer' => __( 'A data practice describes a specific way a company collects, uses, stores, or shares information. Each practice usually spells out what data is involved, why it is collected, how long it is kept, and who it is shared with. Grouping data practices by category, such as account data, usage data, or support data, helps customers understand exactly what happens to their information.', 'open-trust-center-by-ettic' ), ], ]; diff --git a/includes/providers/class-ettic-otc-chat-provider-anthropic.php b/includes/providers/class-ettic-otc-chat-provider-anthropic.php index 8f2de9e..14cc698 100644 --- a/includes/providers/class-ettic-otc-chat-provider-anthropic.php +++ b/includes/providers/class-ettic-otc-chat-provider-anthropic.php @@ -41,7 +41,7 @@ public function slug(): string { } public function label(): string { - return __('Anthropic', 'opentrust'); + return __('Anthropic', 'open-trust-center-by-ettic'); } public function allowed_hosts(): array { @@ -60,7 +60,7 @@ protected function auth_headers(string $key): array { } protected function no_models_message(): string { - return __('No models available — your account may not be authorized.', 'opentrust'); + return __('No models available — your account may not be authorized.', 'open-trust-center-by-ettic'); } public function curate_models(mixed $raw): array { @@ -124,7 +124,7 @@ protected function initialize_turn_loop(array $args, callable $on_chunk): ?array $tools = is_array($args['tools'] ?? null) ? $args['tools'] : []; if ($api_key === '' || $model === '' || empty($messages)) { - $on_chunk(['type' => 'error', 'data' => ['message' => __('Anthropic adapter missing required args.', 'opentrust')]]); + $on_chunk(['type' => 'error', 'data' => ['message' => __('Anthropic adapter missing required args.', 'open-trust-center-by-ettic')]]); return null; } @@ -216,7 +216,7 @@ function (string $line) use (&$turn_state): void { if (empty($response['ok'])) { $on_chunk([ 'type' => 'error', - 'data' => ['message' => $response['error'] ?? __('Anthropic request failed.', 'opentrust')], + 'data' => ['message' => $response['error'] ?? __('Anthropic request failed.', 'open-trust-center-by-ettic')], ]); return null; } @@ -411,8 +411,8 @@ private function handle_anthropic_sse_line(string $line, array &$state): void { $state['tool_intent_emitted'] = true; $tool_name = (string) ($block['name'] ?? ''); $intent_label = $tool_name === 'search_documents' - ? __('Searching documents…', 'opentrust') - : __('Reading documents…', 'opentrust'); + ? __('Searching documents…', 'open-trust-center-by-ettic') + : __('Reading documents…', 'open-trust-center-by-ettic'); ($state['on_chunk'])([ 'type' => 'tool_intent', 'data' => [ diff --git a/includes/providers/class-ettic-otc-chat-provider-openai.php b/includes/providers/class-ettic-otc-chat-provider-openai.php index c009d5a..613ee35 100644 --- a/includes/providers/class-ettic-otc-chat-provider-openai.php +++ b/includes/providers/class-ettic-otc-chat-provider-openai.php @@ -63,7 +63,7 @@ public function slug(): string { } public function label(): string { - return __('OpenAI', 'opentrust'); + return __('OpenAI', 'open-trust-center-by-ettic'); } public function allowed_hosts(): array { @@ -163,7 +163,7 @@ protected function initialize_turn_loop(array $args, callable $on_chunk): ?array $tools = is_array($args['tools'] ?? null) ? $args['tools'] : []; if ($api_key === '' || $model === '' || empty($messages)) { - $on_chunk(['type' => 'error', 'data' => ['message' => __('OpenAI adapter missing required args.', 'opentrust')]]); + $on_chunk(['type' => 'error', 'data' => ['message' => __('OpenAI adapter missing required args.', 'open-trust-center-by-ettic')]]); return null; } @@ -250,7 +250,7 @@ function (string $line) use (&$turn_state): void { if (empty($response['ok'])) { $on_chunk([ 'type' => 'error', - 'data' => ['message' => $response['error'] ?? __('OpenAI request failed.', 'opentrust')], + 'data' => ['message' => $response['error'] ?? __('OpenAI request failed.', 'open-trust-center-by-ettic')], ]); return null; } diff --git a/includes/providers/class-ettic-otc-chat-provider-openrouter.php b/includes/providers/class-ettic-otc-chat-provider-openrouter.php index ea8caf2..577a121 100644 --- a/includes/providers/class-ettic-otc-chat-provider-openrouter.php +++ b/includes/providers/class-ettic-otc-chat-provider-openrouter.php @@ -35,7 +35,7 @@ public function slug(): string { } public function label(): string { - return __('OpenRouter', 'opentrust'); + return __('OpenRouter', 'open-trust-center-by-ettic'); } public function allowed_hosts(): array { diff --git a/includes/providers/class-ettic-otc-chat-provider.php b/includes/providers/class-ettic-otc-chat-provider.php index 7083cb2..47a499b 100644 --- a/includes/providers/class-ettic-otc-chat-provider.php +++ b/includes/providers/class-ettic-otc-chat-provider.php @@ -43,19 +43,19 @@ public static function available(): array { return [ [ 'slug' => 'anthropic', - 'label' => __('Anthropic', 'opentrust'), + 'label' => __('Anthropic', 'open-trust-center-by-ettic'), 'key_url' => 'https://console.anthropic.com/settings/keys', 'recommended' => true, ], [ 'slug' => 'openai', - 'label' => __('OpenAI', 'opentrust'), + 'label' => __('OpenAI', 'open-trust-center-by-ettic'), 'key_url' => 'https://platform.openai.com/api-keys', 'recommended' => false, ], [ 'slug' => 'openrouter', - 'label' => __('OpenRouter', 'opentrust'), + 'label' => __('OpenRouter', 'open-trust-center-by-ettic'), 'key_url' => 'https://openrouter.ai/settings/keys', 'recommended' => false, ], @@ -101,7 +101,7 @@ abstract protected function models_endpoint(): string; * Subclasses override when they want a more specific phrasing. */ protected function no_models_message(): string { - return __('No chat models available for this key.', 'opentrust'); + return __('No chat models available for this key.', 'open-trust-center-by-ettic'); } /** @@ -114,13 +114,13 @@ protected function no_models_message(): string { public function validate_and_list_models(string $key): array { $key = trim($key); if ($key === '') { - return ['ok' => false, 'error' => __('API key is empty.', 'opentrust')]; + return ['ok' => false, 'error' => __('API key is empty.', 'open-trust-center-by-ettic')]; } $response = $this->http_get($this->models_endpoint(), $this->auth_headers($key), 15); if (!$response['ok']) { - return ['ok' => false, 'error' => $response['error'] ?? __('Request failed.', 'opentrust')]; + return ['ok' => false, 'error' => $response['error'] ?? __('Request failed.', 'open-trust-center-by-ettic')]; } $models = $this->curate_models($response['body']); @@ -265,7 +265,7 @@ final protected function emit_cap_refusal(callable $on_chunk): void { $on_chunk([ 'type' => 'token', 'data' => [ - 'text' => __("I couldn't find a confident answer in the published trust center documents. Please contact the team for help.", 'opentrust'), + 'text' => __("I couldn't find a confident answer in the published trust center documents. Please contact the team for help.", 'open-trust-center-by-ettic'), ], ]); } @@ -339,19 +339,19 @@ protected static function summarize_tool_call(string $name, array $args, array $ if ($title !== '') { return $is_settled /* translators: %s is the document title. */ - ? sprintf(__('Read "%s"', 'opentrust'), $title) + ? sprintf(__('Read "%s"', 'open-trust-center-by-ettic'), $title) /* translators: %s is the document title. */ - : sprintf(__('Reading "%s"', 'opentrust'), $title); + : sprintf(__('Reading "%s"', 'open-trust-center-by-ettic'), $title); } } } return $is_settled /* translators: %s is the document id. */ - ? sprintf(__('Read %s', 'opentrust'), $id) + ? sprintf(__('Read %s', 'open-trust-center-by-ettic'), $id) /* translators: %s is the document id. */ - : sprintf(__('Reading %s', 'opentrust'), $id); + : sprintf(__('Reading %s', 'open-trust-center-by-ettic'), $id); } - return $is_settled ? __('Read a document', 'opentrust') : __('Reading a document', 'opentrust'); + return $is_settled ? __('Read a document', 'open-trust-center-by-ettic') : __('Reading a document', 'open-trust-center-by-ettic'); } if ($name === 'search_documents') { @@ -364,11 +364,11 @@ protected static function summarize_tool_call(string $name, array $args, array $ } return $is_settled /* translators: %s is the search query. */ - ? sprintf(__('Searched for "%s"', 'opentrust'), $q) + ? sprintf(__('Searched for "%s"', 'open-trust-center-by-ettic'), $q) /* translators: %s is the search query. */ - : sprintf(__('Searching for "%s"', 'opentrust'), $q); + : sprintf(__('Searching for "%s"', 'open-trust-center-by-ettic'), $q); } - return $is_settled ? __('Searched documents', 'opentrust') : __('Searching documents', 'opentrust'); + return $is_settled ? __('Searched documents', 'open-trust-center-by-ettic') : __('Searching documents', 'open-trust-center-by-ettic'); } return $name; @@ -396,22 +396,22 @@ protected static function summarize_turn_batch(array $names, int $count, string if ($all_get) { return $is_settled /* translators: %d is the number of documents that were read in parallel. */ - ? sprintf(__('Read %d documents', 'opentrust'), $count) + ? sprintf(__('Read %d documents', 'open-trust-center-by-ettic'), $count) /* translators: %d is the number of documents being read in parallel. */ - : sprintf(__('Reading %d documents', 'opentrust'), $count); + : sprintf(__('Reading %d documents', 'open-trust-center-by-ettic'), $count); } if ($all_search) { return $is_settled /* translators: %d is the number of search queries that were fired in parallel. */ - ? sprintf(__('Ran %d searches', 'opentrust'), $count) + ? sprintf(__('Ran %d searches', 'open-trust-center-by-ettic'), $count) /* translators: %d is the number of search queries fired in parallel. */ - : sprintf(__('Running %d searches', 'opentrust'), $count); + : sprintf(__('Running %d searches', 'open-trust-center-by-ettic'), $count); } return $is_settled /* translators: %d is the number of parallel retrieval calls (mixed types). */ - ? sprintf(__('Ran %d retrievals', 'opentrust'), $count) + ? sprintf(__('Ran %d retrievals', 'open-trust-center-by-ettic'), $count) /* translators: %d is the number of parallel retrieval calls (mixed types). */ - : sprintf(__('Running %d retrievals', 'opentrust'), $count); + : sprintf(__('Running %d retrievals', 'open-trust-center-by-ettic'), $count); } // ────────────────────────────────────────────── @@ -440,7 +440,7 @@ final protected function host_allowed(string $url): bool { */ final protected function http_get(string $url, array $headers = [], int $timeout = 15): array { if (!$this->host_allowed($url)) { - return ['ok' => false, 'error' => __('Refused outbound request to disallowed host.', 'opentrust')]; + return ['ok' => false, 'error' => __('Refused outbound request to disallowed host.', 'open-trust-center-by-ettic')]; } $response = wp_safe_remote_get($url, [ @@ -459,7 +459,7 @@ final protected function http_get(string $url, array $headers = [], int $timeout */ final protected function http_post(string $url, array $payload, array $headers = [], int $timeout = 60): array { if (!$this->host_allowed($url)) { - return ['ok' => false, 'error' => __('Refused outbound request to disallowed host.', 'opentrust')]; + return ['ok' => false, 'error' => __('Refused outbound request to disallowed host.', 'open-trust-center-by-ettic')]; } $headers = array_merge(['Content-Type' => 'application/json'], $headers); @@ -510,12 +510,12 @@ final protected function normalize_response(mixed $response): array { */ final protected function stream_post(string $url, array $payload, array $headers, callable $on_line, int $timeout = 90): array { if (!$this->host_allowed($url)) { - return ['ok' => false, 'error' => __('Refused outbound request to disallowed host.', 'opentrust')]; + return ['ok' => false, 'error' => __('Refused outbound request to disallowed host.', 'open-trust-center-by-ettic')]; } // SSE chunk callbacks require cURL transport. Streams/fsockopen buffer the full response. if (!function_exists('curl_init')) { - return ['ok' => false, 'error' => __('AI streaming requires the PHP cURL extension.', 'opentrust')]; + return ['ok' => false, 'error' => __('AI streaming requires the PHP cURL extension.', 'open-trust-center-by-ettic')]; } $body = wp_json_encode($payload); @@ -617,7 +617,7 @@ final protected function stream_post(string $url, array $payload, array $headers // If WP picked Streams/fsockopen, http_api_curl never fired and our SSE callbacks // never installed — the response body was buffered, not streamed. Fail loudly. if (!$state->curl_hook_ran) { - return ['ok' => false, 'error' => __('AI streaming requires the WordPress cURL transport.', 'opentrust')]; + return ['ok' => false, 'error' => __('AI streaming requires the WordPress cURL transport.', 'open-trust-center-by-ettic')]; } // Copy parsed response headers (Requests' stream_headers still ran since we @@ -670,7 +670,7 @@ final protected function stream_post(string $url, array $payload, array $headers */ final protected function describe_streaming_error(string $body, array $headers, int $code): string { /* translators: %d: HTTP status code returned by the provider */ - $parts = [sprintf(__('Provider returned HTTP %d', 'opentrust'), $code)]; + $parts = [sprintf(__('Provider returned HTTP %d', 'open-trust-center-by-ettic'), $code)]; $body = trim($body); if ($body !== '') { @@ -725,6 +725,6 @@ protected function extract_error_message(mixed $body, int $code): string { } } /* translators: %d: HTTP status code returned by the provider */ - return sprintf(__('Provider returned HTTP %d', 'opentrust'), $code); + return sprintf(__('Provider returned HTTP %d', 'open-trust-center-by-ettic'), $code); } } diff --git a/languages/open-trust-center-by-ettic-nl_NL.mo b/languages/open-trust-center-by-ettic-nl_NL.mo new file mode 100644 index 0000000000000000000000000000000000000000..f2e88753c468081eed008f5fdd73aa8c39b887b2 GIT binary patch literal 543 zcmaJ;O>Yx15G|soJ#ywSl{mD5+0Cw6lsW{V<^x4a+NfHfx60WaHj5m4HTDAeA^bgV z{U05-sJ$`LlWqCU^PA_tuMYnlNWBoe7Q7L>6uc9}8Vc^@@?6%)d8#$LA5;Zg)cBRy zx6UfK>c~RLy$>)U8;D`Ehgk@11$kPegXEez#{pNqX=}Xb8;_+^unnQ}D$9O3t~)00 zQ^!r_`!15R&h$-dGbh>@qBd3!+PK*xMeSsLh1c}6jUI5S11Ts5#d{o_VtxumuFlTh z4y2N$mgbVR^+pHB>YueuZ)-y}_@Fs@{$L$bXZD{S)KhCdN~djl-4K?fcM7I`sJ3u? zNnuNDw5|Qg6GeeFx0lOgwOGxblgVZHiIYgIIM{b$G0^Wgn{Mq0s;y>EVf>|>\n" +"Language-Team: Dutch (Netherlands)\n" +"Language: nl_NL\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: WP-CLI 2.12.0\n" +"X-Domain: open-trust-center-by-ettic\n" + +#. Plugin Name of the plugin +#: open-trust-center-by-ettic.php +msgid "Open Trust Center by Ettic" +msgstr "" + +#. Plugin URI of the plugin +#: open-trust-center-by-ettic.php +msgid "https://plugins.ettic.nl/open-trust-center-by-ettic" +msgstr "" + +#. Description of the plugin +#: open-trust-center-by-ettic.php +#, fuzzy +msgid "" +"A self-hosted, open-source trust center for publishing security policies, " +"subprocessors, certifications, and data practices." +msgstr "" +"Een zelf-gehost, open-source vertrouwenscentrum voor het publiceren van " +"beveiligingsbeleid, subverwerkers, certificeringen en gegevenspraktijken." + +#. Author of the plugin +#: open-trust-center-by-ettic.php +msgid "Ettic" +msgstr "" + +#. Author URI of the plugin +#: open-trust-center-by-ettic.php +msgid "https://plugins.ettic.nl" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:78 +msgid "Heads up: citation fidelity is not guaranteed on your active provider." +msgstr "" + +#. translators: %s: provider label, e.g. OpenAI +#: includes/class-ettic-otc-admin-ai.php:83 +#, php-format +msgid "" +"You are currently using %s. Only Anthropic uses a " +"structural Citations API — every other provider relies on prompted citation " +"tags the model can ignore or fabricate. For a published trust center, switch " +"to Anthropic below." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:94 +msgid "" +"Ettic_OTC uses Anthropic Claude with the native Citations API to answer visitor questions about your trust center. Every claim the " +"assistant makes is tied to an exact quote from one of your published " +"documents — so no policy text is invented and nothing is paraphrased into " +"something you did not actually publish." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:101 +msgid "Why Anthropic, and not OpenAI or any other provider?" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:106 +msgid "" +"A trust center is a compliance surface. If the assistant " +"invents a security commitment you never made, that is not a UX papercut — it " +"is a misrepresentation of your security posture, and your customers and " +"auditors will hold you to it." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:114 +msgid "" +"Anthropic is the only major provider that exposes a " +"structural Citations API. Documents are sent as typed blocks and the model " +"emits citations as first-class events containing the exact source document " +"and the exact quoted text. The model literally cannot return a citation for " +"text that is not in your source documents." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:120 +msgid "" +"Every other provider (including OpenAI and any model accessed via " +"OpenRouter) relies on prompted citation tags that we parse out of the answer " +"after the fact. That works most of the time, but the model can ignore the " +"instructions, make up document IDs, or attach a citation to a sentence it " +"actually hallucinated. We support these providers as an escape hatch for " +"organizations that genuinely cannot use Anthropic for procurement or data-" +"residency reasons — but we very, very strongly recommend you do not run a " +"public trust center on them." +msgstr "" + +#. translators: %d is the number of policies missing AI summaries. +#: includes/class-ettic-otc-admin-ai.php:159 +#, php-format +msgid "%d policy is missing an AI summary." +msgid_plural "%d policies are missing AI summaries." +msgstr[0] "" +msgstr[1] "" + +#: includes/class-ettic-otc-admin-ai.php:170 +msgid "Generate them now so the assistant can route questions accurately." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:175 +msgid "Generate now" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:199 +msgid "Choose a provider and add your key" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:211 +msgid "Step 1 — Connect Anthropic" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:217 +msgid "Advanced: use a different provider (not recommended)" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:220 +msgid "These providers cannot guarantee citation fidelity." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:222 +msgid "" +"OpenAI and OpenRouter rely on prompted [[cite:document-id]] tags that we " +"parse out of the answer after generation. The model can ignore the " +"instruction, invent document IDs, or attach a citation to a sentence it " +"actually hallucinated. We cannot detect when this happens." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:225 +msgid "Do not use these providers for a published trust center" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:226 +msgid "" +"unless your organization genuinely cannot use Anthropic for procurement, " +"contractual, or data-residency reasons. Inaccurate claims about your " +"security posture are a real compliance risk." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:265 +msgid "Required for citation fidelity" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:271 +msgid "" +"Uses Claude with the native Citations API. Every quote the assistant " +"attributes to one of your documents is structurally guaranteed to come from " +"that document." +msgstr "" + +#. translators: %s: provider name (e.g. Anthropic) +#: includes/class-ettic-otc-admin-ai.php:279 +#, php-format +msgid "Get a %s API key" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:292 +msgid "Remove the saved key for this provider?" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:293 +msgid "Replace key" +msgstr "" + +#. translators: %s: provider name (e.g. Anthropic) +#: includes/class-ettic-otc-admin-ai.php:303 +#, php-format +msgid "Paste your %s API key…" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:307 +msgid "Validate & save" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:346 +msgid "Step 2 — Pick a model and tune defaults" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:359 +msgid "Active model" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:363 +msgid "No cached models found. Use Refresh to re-fetch the model list." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:372 +msgid "(unavailable)" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:376 +msgid "Recommended" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:387 +msgid "Model unavailable" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:392 +msgid "Refresh models" +msgstr "" + +#. translators: %s: human-readable time difference (e.g. "5 minutes") +#: includes/class-ettic-otc-admin-ai.php:402 +#, php-format +msgid "Model list cached %s ago." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:410 +msgid "Daily token budget" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:413 +msgid "" +"Hard cap per site per day. Default 500,000 tokens (~$12/day at Sonnet 4.5 " +"rates)." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:417 +msgid "Monthly token budget" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:420 +msgid "Hard cap per site per month. Default 10,000,000 tokens." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:424 +msgid "Rate limit — per IP" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:426 +msgid "messages per minute" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:430 +msgid "Rate limit — per session" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:432 +msgid "messages per hour" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:436 +msgid "Max message length" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:438 +msgid "characters" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:443 +msgid "Refuse-to-answer contact URL" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:446 +msgid "" +"When the AI cannot confidently answer a question, it links here. Leave blank " +"to use the trust center home." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:451 +msgid "Visitor display" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:455 +msgid "Show the active model name under the chat input" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:461 +msgid "Analytics logging" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:465 +msgid "" +"Log anonymized visitor questions for admin review (90-day auto-purge, no PII)" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:471 +msgid "Improve answer quality" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:475 +msgid "Generate AI summaries of each policy" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:478 +msgid "" +"When on, the AI generates a 2–3 sentence summary of each published policy " +"and stores it for routing decisions. Improves answers on questions like " +"\"What's your data deletion policy?\" that don't match a title literally. " +"Cost is roughly $0.05–$0.10 per 50 policies, lifetime — pennies per edit " +"afterward. Uses your configured AI key." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:487 +msgid "Oversized policies" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:491 +msgid "" +"The following policies are large enough that the AI will receive only a " +"truncated version when retrieving them. Consider splitting them into shorter " +"documents:" +msgstr "" + +#. translators: 1: policy title, 2: token count. +#: includes/class-ettic-otc-admin-ai.php:498 +#, php-format +msgid "%1$s (~%2$s tokens)" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:512 +msgid "Advanced — Turnstile anti-abuse" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:514 +msgid "" +"Cloudflare Turnstile is optional but recommended for public sites. It " +"challenges suspicious visitors on the first message of each session. You " +"need a free Cloudflare account to get site/secret keys." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:518 +msgid "Enable Turnstile for chat" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:522 +msgid "Require Turnstile verification on first chat message" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:527 +msgid "Turnstile Site Key" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:530 +msgid "Public site key from your Cloudflare Turnstile widget." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:534 +msgid "Turnstile Secret Key" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:537 +msgid "Enter secret key…" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:539 +msgid "Key saved" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:541 +msgid "" +"Secret key from Cloudflare Turnstile. Stored server-side — never exposed to " +"the frontend." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:546 +msgid "Save AI settings" +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:657 +#: includes/class-ettic-otc-admin-ai.php:714 +#: includes/class-ettic-otc-admin-ai.php:751 +#: includes/class-ettic-otc-admin-ai.php:796 +#: includes/class-ettic-otc-admin-questions.php:223 +#: includes/class-ettic-otc-admin-questions.php:264 +#: includes/class-ettic-otc-admin-questions.php:281 +#: includes/class-ettic-otc-admin-tools.php:565 +msgid "You do not have permission to perform this action." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:666 +#: includes/class-ettic-otc-admin-ai.php:722 +#: includes/class-ettic-otc-admin-ai.php:758 +msgid "Unknown provider." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:670 +msgid "API key cannot be empty." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:677 +msgid "Validation failed." +msgstr "" + +#. translators: 1: provider label, 2: provider error message +#: includes/class-ettic-otc-admin-ai.php:679 +#, php-format +msgid "%1$s rejected the key: %2$s" +msgstr "" + +#. translators: 1: provider label, 2: number of models +#: includes/class-ettic-otc-admin-ai.php:707 +#, php-format +msgid "%1$s key validated. Found %2$d model(s)." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:745 +msgid "Key removed." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:764 +msgid "No key on file for this provider." +msgstr "" + +#: includes/class-ettic-otc-admin-ai.php:770 +msgid "Refresh failed." +msgstr "" + +#. translators: %s: error message from the provider +#: includes/class-ettic-otc-admin-ai.php:772 +#, php-format +msgid "Refresh failed: %s" +msgstr "" + +#. translators: %d: number of models +#: includes/class-ettic-otc-admin-ai.php:782 +#, php-format +msgid "Model list refreshed. Found %d model(s)." +msgstr "" + +#. translators: %d is the number of policies enqueued for summary generation. +#: includes/class-ettic-otc-admin-ai.php:812 +#, php-format +msgid "" +"Queued %d policy for AI summary generation. Summaries will appear over the " +"next minute." +msgid_plural "" +"Queued %d policies for AI summary generation. Summaries will appear over the " +"next few minutes." +msgstr[0] "" +msgstr[1] "" + +#: includes/class-ettic-otc-admin-ai.php:820 +msgid "All policies already have up-to-date AI summaries." +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:87 +msgid "AI Questions" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:90 +msgid "" +"Questions visitors have asked your trust center chat. Identifiers are hashed " +"and rows auto-purge after 90 days." +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:96 +msgid "Logging is ON" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:98 +msgid "Logging is OFF" +msgstr "" + +#. translators: %d: number of questions +#: includes/class-ettic-otc-admin-questions.php:104 +#, php-format +msgid "%d question logged in the last 90 days" +msgid_plural "%d questions logged in the last 90 days" +msgstr[0] "" +msgstr[1] "" + +#: includes/class-ettic-otc-admin-questions.php:108 +msgid "Toggle visitor question logging?" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:109 +msgid "Disable logging" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:109 +msgid "Enable logging" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:117 +#, fuzzy +msgid "Search" +msgstr "Zoeken" + +#: includes/class-ettic-otc-admin-questions.php:118 +msgid "Search questions…" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:121 +#: includes/class-ettic-otc-admin-questions.php:148 +msgid "Model" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:123 +msgid "Any" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:130 +msgid "From" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:134 +msgid "To" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:137 +msgid "Filter" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:138 +msgid "Reset" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:139 +msgid "Download CSV" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:146 +#: includes/class-ettic-otc-version.php:161 +msgid "Date" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:147 +msgid "Question" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:149 +msgid "Cites" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:150 +msgid "Tokens" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:151 +msgid "Latency" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:156 +msgid "No questions logged yet." +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:165 +msgid "REFUSED" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:209 +msgid "Danger zone" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:210 +msgid "Permanently delete all logged questions? This cannot be undone." +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:211 +msgid "Clear entire question log" +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:272 +msgid "Question log cleared." +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:291 +msgid "Logging enabled." +msgstr "" + +#: includes/class-ettic-otc-admin-questions.php:291 +msgid "Logging disabled." +msgstr "" + +#: includes/class-ettic-otc-admin-review.php:81 +msgid "review on WordPress.org" +msgstr "" + +#. translators: %s: link to the WordPress.org reviews page +#: includes/class-ettic-otc-admin-review.php:89 +#, php-format +msgid "" +"Ettic_OTC is built and maintained in the open. If it is helping your team, a " +"%s keeps the project moving." +msgstr "" + +#: includes/class-ettic-otc-admin-review.php:115 +msgid "Your trust center is up and running." +msgstr "" + +#: includes/class-ettic-otc-admin-review.php:116 +msgid "" +"Ettic_OTC is fully open-source with no paid tier — reviews on WordPress.org " +"are how the project gets seen. If it has earned a kind word, we would be " +"grateful." +msgstr "" + +#: includes/class-ettic-otc-admin-review.php:120 +msgid "Leave a review" +msgstr "" + +#: includes/class-ettic-otc-admin-review.php:123 +msgid "Already did, thanks" +msgstr "" + +#: includes/class-ettic-otc-admin-review.php:126 +msgid "Not now" +msgstr "" + +#: includes/class-ettic-otc-admin-review.php:168 +msgid "You do not have permission to dismiss this notice." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:55 +msgid "General Settings" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:60 +msgid "Endpoint Slug" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:61 +msgid "" +"The URL path for your trust center (e.g., \"trust-center\" = yoursite.com/" +"trust-center/)." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:64 +msgid "Page Title" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:66 +msgid "Company Name" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:68 +msgid "Tagline" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:69 +msgid "" +"A short description displayed below the company name in the hero section." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:75 +msgid "Branding" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:80 +msgid "Logo" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:81 +msgid "AI Avatar" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:83 +msgid "Accent Color" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:84 +msgid "" +"Used for buttons, links, and highlights. Choose a color that matches your " +"brand." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:87 +msgid "Credit Link" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:92 +msgid "Visible Sections" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:93 +msgid "Choose which sections to display on the trust center." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:97 +msgid "Sections" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:103 +#: templates/partials/contact.php:111 +msgid "Get in touch" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:104 +msgid "" +"Publish a dark-accent \"Get in touch\" block on the trust center. Every " +"field is optional — the block only appears if at least one is filled in." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:108 +msgid "Company Description" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:109 +msgid "" +"Two or three sentences describing what the company does. Rendered under the " +"\"Get in touch\" section title." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:112 +msgid "DPO Name" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:113 +msgid "" +"Data Protection Officer name. Required under GDPR for many organisations." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:116 +msgid "DPO Email" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:117 +msgid "Dedicated DPO mailbox. Rendered as a mailto link." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:120 +msgid "Security Contact Email" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:121 +msgid "" +"For vulnerability reports and security questions. Often separate from the " +"DPO." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:124 +msgid "Contact Form URL" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:125 +msgid "Optional link to a gated contact form." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:128 +#: templates/partials/contact.php:84 +msgid "Mailing Address" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:129 +msgid "Postal address for formal GDPR / legal notices." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:132 +msgid "PGP Public Key URL" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:133 +msgid "Optional link to your security team's PGP public key." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:136 +msgid "Company Registration Number" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:137 +msgid "" +"KvK (NL), Companies House (UK), Handelsregister (DE), EIN (US), or " +"equivalent business registration." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:140 +#: templates/partials/contact.php:100 +msgid "VAT / Tax ID" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:141 +msgid "VAT number, sales-tax ID, or equivalent international tax identifier." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:222 +msgid "Low contrast on white backgrounds" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:223 +msgid "Using your exact color on white backgrounds" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:226 +msgid "" +"Your chosen color is too light for buttons, links, and borders on white " +"sections. On those surfaces Ettic_OTC will use a darker, on-brand variant:" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:229 +msgid "" +"You've chosen to keep your exact color on white backgrounds. Buttons, links, " +"and borders in those sections may be hard to read." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:241 +msgid "The hero and navigation still use your exact color." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:252 +msgid "Use my exact color anyway — skip the contrast adjustment." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:265 +#: includes/class-ettic-otc-cpt.php:475 +msgid "Select Logo" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:266 +msgid "" +"Used in the hero and sticky nav. A white version is recommended — it sits on " +"a dark background." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:273 +msgid "Select Avatar" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:274 +msgid "" +"Square image used as the avatar on AI chat responses. Use a colored " +"background with a light or dark favicon or logo on top." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:289 +#: includes/class-ettic-otc-cpt.php:476 includes/class-ettic-otc-cpt.php:488 +#: includes/class-ettic-otc-cpt.php:619 includes/class-ettic-otc-cpt.php:635 +#: includes/class-ettic-otc-cpt.php:721 includes/class-ettic-otc-cpt.php:759 +msgid "Remove" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:301 +msgid "" +"Show a \"Powered by Open Trust Center\" credit in the trust center footer." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:305 +msgid "Off by default. Public credits are opt-in." +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:314 +#: templates/partials/certifications.php:22 +#, fuzzy +msgid "Certifications & Compliance" +msgstr "Certificeringen & compliance" + +#: includes/class-ettic-otc-admin-settings.php:315 +#: includes/class-ettic-otc-admin-tools.php:592 +#: includes/class-ettic-otc-cpt.php:236 includes/class-ettic-otc-cpt.php:246 +#: templates/chat.php:45 templates/partials/hero.php:55 +#: templates/trust-center.php:107 +#, fuzzy +msgid "Policies" +msgstr "Beleid" + +#: includes/class-ettic-otc-admin-settings.php:316 +#: includes/class-ettic-otc-admin-tools.php:594 +#: includes/class-ettic-otc-cpt.php:303 includes/class-ettic-otc-cpt.php:312 +#: templates/chat.php:47 templates/partials/hero.php:61 +#: templates/partials/subprocessors.php:20 templates/trust-center.php:109 +#, fuzzy +msgid "Subprocessors" +msgstr "Subverwerkers" + +#: includes/class-ettic-otc-admin-settings.php:317 +#: includes/class-ettic-otc-admin-tools.php:595 +#: includes/class-ettic-otc-cpt.php:336 includes/class-ettic-otc-cpt.php:345 +#: templates/chat.php:48 templates/partials/data-practices.php:34 +#: templates/trust-center.php:110 +#, fuzzy +msgid "Data Practices" +msgstr "Gegevensverwerking" + +#: includes/class-ettic-otc-admin-settings.php:318 +#: includes/class-ettic-otc-admin-tools.php:596 +#: includes/class-ettic-otc-cpt.php:369 includes/class-ettic-otc-cpt.php:379 +msgid "FAQs" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:319 +msgid "Contact & DPO" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:586 +msgid "View Trust Center" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:593 +#: includes/class-ettic-otc-render.php:515 +msgid "General" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:597 templates/chat.php:60 +#: templates/trust-center.php:111 +msgid "Contact" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:601 +msgid "AI Chat" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:604 +msgid "Live" +msgstr "" + +#: includes/class-ettic-otc-admin-settings.php:610 +msgid "Import & Export" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:155 +msgid "" +"Move trust center content and settings between sites, or seed a fresh " +"install from another. API keys and the Turnstile secret are never included — " +"re-enter them on the destination." +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:163 +msgid "Export" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:167 +msgid "Import" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:183 +msgid "What to export" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:186 +msgid "Content (CPTs + bundled media)" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:190 +msgid "Settings only" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:195 +msgid "Content selection" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:225 +msgid "Bundle attached PDFs and images" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:229 +msgid "Download export" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:243 +msgid "Only upload your own exports." +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:244 +msgid "" +"Export files contain your trust-center content and may include sensitive " +"material. Never import a file you received from someone else." +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:248 +msgid "Upload export file" +msgstr "" + +#. translators: %d: max upload size in MB +#: includes/class-ettic-otc-admin-tools.php:253 +#, php-format +msgid "Max %d MB" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:259 +msgid "On conflict" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:262 +msgid "Skip — keep existing records untouched" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:266 +msgid "Overwrite — replace existing records" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:270 +msgid "Create new — duplicate with a -import suffix" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:275 +msgid "Preview import" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:292 +msgid "Import preview" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:296 +msgid "Import blocked:" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:317 +msgid "" +"Settings export — current values will be merged with imported values. " +"Excluded keys (encrypted secrets, salt, server-controlled flags) are kept as-" +"is." +msgstr "" + +#. translators: %1$d: create count, %2$d: update count, %3$d: skip count +#: includes/class-ettic-otc-admin-tools.php:324 +#, php-format +msgid "Will create %1$d, update %2$d, skip %3$d." +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:338 +msgid "Title" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:339 +msgid "Action" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:340 +msgid "UUID" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:361 +msgid "Confirm and import" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:363 +msgid "Cancel" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:385 +msgid "Pick at least one record to export." +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:415 +msgid "No file uploaded." +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:421 +msgid "Upload exceeds size limit." +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:514 +msgid "Import cancelled." +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:519 +msgid "Import has unresolved errors." +msgstr "" + +#. translators: %1$d: created, %2$d: updated, %3$d: skipped +#: includes/class-ettic-otc-admin-tools.php:539 +#, php-format +msgid "Imported: %1$d created, %2$d updated, %3$d skipped." +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:547 +msgid "Errors:" +msgstr "" + +#: includes/class-ettic-otc-admin-tools.php:593 +#: includes/class-ettic-otc-cpt.php:270 includes/class-ettic-otc-cpt.php:279 +#: templates/chat.php:46 templates/partials/hero.php:49 +#: templates/trust-center.php:108 +#, fuzzy +msgid "Certifications" +msgstr "Certificeringen" + +#: includes/class-ettic-otc-admin.php:56 includes/class-ettic-otc-admin.php:57 +msgid "Open Trust Center" +msgstr "" + +#: includes/class-ettic-otc-admin.php:67 includes/class-ettic-otc-admin.php:68 +msgid "Settings" +msgstr "" + +#: includes/class-ettic-otc-admin.php:79 includes/class-ettic-otc-admin.php:80 +msgid "Questions" +msgstr "" + +#: includes/class-ettic-otc-admin.php:158 +msgid "Select Badge Image" +msgstr "" + +#: includes/class-ettic-otc-admin.php:159 +msgid "Use as Badge" +msgstr "" + +#: includes/class-ettic-otc-admin.php:160 +msgid "Select Proof Artifact" +msgstr "" + +#: includes/class-ettic-otc-admin.php:161 +msgid "Use This File" +msgstr "" + +#: includes/class-ettic-otc-admin.php:162 includes/class-ettic-otc-cpt.php:487 +msgid "Upload File" +msgstr "" + +#: includes/class-ettic-otc-admin.php:163 includes/class-ettic-otc-cpt.php:487 +msgid "Replace File" +msgstr "" + +#: includes/class-ettic-otc-admin.php:178 +msgid "No match in catalog, just keep typing to add manually." +msgstr "" + +#: includes/class-ettic-otc-admin.php:179 +msgid "Auto-filled from catalog, you may want to verify this." +msgstr "" + +#: includes/class-ettic-otc-admin.php:180 +msgid "" +"Auto-filled template, please verify this matches how you use this service." +msgstr "" + +#: includes/class-ettic-otc-admin.php:181 +msgid "click to autofill" +msgstr "" + +#: includes/class-ettic-otc-admin.php:182 +msgid "Catalog suggestions" +msgstr "" + +#: includes/class-ettic-otc-admin.php:228 +msgid "Ettic_OTC requires pretty permalinks." +msgstr "" + +#. translators: %s: link to Settings → Permalinks +#: includes/class-ettic-otc-admin.php:232 +#, php-format +msgid "" +"Your site is using \"Plain\" permalinks. Please go to %s and choose any " +"other option (Post name is the WordPress default)." +msgstr "" + +#: includes/class-ettic-otc-admin.php:233 +msgid "Settings → Permalinks" +msgstr "" + +#: includes/class-ettic-otc-admin.php:238 +msgid "" +"Without pretty permalinks, every link Ettic_OTC generates returns 404 — " +"including the trust center page itself. Visitors will not be able to reach " +"your policies, certifications, or chat." +msgstr "" + +#: includes/class-ettic-otc-admin.php:242 +msgid "Read-only fallback if you cannot change permalinks" +msgstr "" + +#: includes/class-ettic-otc-admin.php:246 +msgid "You can preview the trust center via raw query-string URLs:" +msgstr "" + +#: includes/class-ettic-otc-admin.php:254 +msgid "This is for testing only." +msgstr "" + +#: includes/class-ettic-otc-admin.php:255 +msgid "Switching to pretty permalinks is the only supported configuration." +msgstr "" + +#: includes/class-ettic-otc-chat.php:112 +#, fuzzy +msgid "Invalid nonce — refresh the page and try again." +msgstr "Ongeldige nonce — ververs de pagina en probeer opnieuw." + +#: includes/class-ettic-otc-chat.php:140 +#, fuzzy +msgid "Please complete the anti-abuse challenge and try again." +msgstr "Voltooi de anti-misbruikcontrole en probeer opnieuw." + +#: includes/class-ettic-otc-chat.php:152 +msgid "You are sending messages too fast. Please wait a moment and try again." +msgstr "" + +#: includes/class-ettic-otc-chat.php:163 +msgid "" +"You have reached the per-session message limit. Please wait a bit and try " +"again." +msgstr "" + +#: includes/class-ettic-otc-chat.php:183 +msgid "AI chat is not configured on this site." +msgstr "" + +#: includes/class-ettic-otc-chat.php:192 +msgid "Configured provider is unknown." +msgstr "" + +#: includes/class-ettic-otc-chat.php:201 +msgid "No API key stored for the configured provider." +msgstr "" + +#: includes/class-ettic-otc-chat.php:214 +msgid "Your message is empty." +msgstr "" + +#: includes/class-ettic-otc-chat.php:232 +msgid "" +"The daily chat budget for this site has been reached. Please try again later." +msgstr "" + +#: includes/class-ettic-otc-chat.php:394 +msgid "Chat provider failed unexpectedly." +msgstr "" + +#. translators: %s is the tool name (get_document or search_documents). +#: includes/class-ettic-otc-chat.php:722 +#, php-format +msgid "" +"You already called %s with the same arguments earlier in this conversation. " +"Pick a different document id from the index, or rephrase the search query " +"with different keywords." +msgstr "" + +#: includes/class-ettic-otc-chat.php:732 +msgid "Document id is required." +msgstr "" + +#. translators: %s is the requested document id. +#: includes/class-ettic-otc-chat.php:741 +#, php-format +msgid "" +"No document with id \"%s\". Pick one of the ids listed in the corpus index " +"above." +msgstr "" + +#: includes/class-ettic-otc-chat.php:749 +msgid "Search query is empty." +msgstr "" + +#: includes/class-ettic-otc-chat.php:752 +msgid "Search index unavailable." +msgstr "" + +#. translators: %s is the search query. +#: includes/class-ettic-otc-chat.php:758 +#, php-format +msgid "" +"No documents matched \"%s\". Try broader keywords or pick a document id from " +"the corpus index above." +msgstr "" + +#: includes/class-ettic-otc-chat.php:770 +msgid "Search ranking returned no usable results." +msgstr "" + +#. translators: %s is the unknown tool name. +#: includes/class-ettic-otc-chat.php:775 +#, php-format +msgid "Unknown tool: %s" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:217 +msgid "Pick from the catalog or type your own subprocessor name" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:220 +msgid "" +"Pick from the catalog or type your own, e.g. Analytics or Transactional Email" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:223 +msgid "Pick from the catalog or type your own, e.g. SOC 2 Type II or ISO 27001" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:237 templates/partials/policies.php:54 +#, fuzzy +msgid "Policy" +msgstr "Beleid" + +#: includes/class-ettic-otc-cpt.php:238 +msgid "Add Policy" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:239 +msgid "Add New Policy" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:240 +msgid "Edit Policy" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:241 +msgid "New Policy" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:242 +#, fuzzy +msgid "View Policy" +msgstr "Beleid bekijken" + +#: includes/class-ettic-otc-cpt.php:243 +msgid "Search Policies" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:244 +msgid "No policies found." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:245 +msgid "No policies in trash." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:271 +msgid "Certification" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:272 +msgid "Add Certification" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:273 +msgid "Add New Certification" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:274 +msgid "Edit Certification" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:275 +msgid "New Certification" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:276 +msgid "Search Certifications" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:277 +msgid "No certifications found." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:278 +msgid "No certifications in trash." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:304 +msgid "Subprocessor" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:305 +msgid "Add Subprocessor" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:306 +msgid "Add New Subprocessor" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:307 +msgid "Edit Subprocessor" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:308 +msgid "New Subprocessor" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:309 +msgid "Search Subprocessors" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:310 +msgid "No subprocessors found." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:311 +msgid "No subprocessors in trash." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:337 +msgid "Data Practice" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:338 +msgid "Add Data Practice" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:339 +msgid "Add New Data Practice" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:340 +msgid "Edit Data Practice" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:341 +msgid "New Data Practice" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:342 +msgid "Search Data Practices" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:343 +msgid "No data practices found." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:344 +msgid "No data practices in trash." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:370 templates/chat.php:61 +#: templates/trust-center.php:112 +msgid "FAQ" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:371 +msgid "Add FAQ" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:372 +msgid "Add New FAQ" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:373 +msgid "Edit FAQ" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:374 +msgid "New FAQ" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:375 +msgid "View FAQ" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:376 +msgid "Search FAQs" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:377 +msgid "No FAQs found." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:378 +msgid "No FAQs in trash." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:401 +msgid "Certification Details" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:402 +msgid "Policy Details" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:403 +msgid "Subprocessor Details" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:404 +msgid "Data Practice Details" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:405 +msgid "FAQ Details" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:426 +msgid "Audited certification (issued by a third party)" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:427 +msgid "Self-attested alignment (no external audit)" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:431 +msgid "Active / currently met" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:432 +msgid "In progress" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:433 +msgid "Expired / lapsed" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:437 +msgid "Certification Type" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:443 +msgid "" +"Audited means a third-party issued a formal certificate with dates (SOC 2, " +"ISO 27001, PCI DSS). Self-attested means you adhere to the framework without " +"an external audit — the honest framing for GDPR, CCPA, and most HIPAA " +"posture claims." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:447 includes/class-ettic-otc-cpt.php:1022 +#, fuzzy +msgid "Status" +msgstr "Status" + +#: includes/class-ettic-otc-cpt.php:453 +msgid "" +"\"Active\" for audited means you hold a current certificate. \"Active\" for " +"self-attested means you currently meet the framework. Use \"In progress\" " +"while working toward either." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:457 includes/class-ettic-otc-cpt.php:1021 +#, fuzzy +msgid "Issuing Body" +msgstr "Uitgegeven door" + +#: includes/class-ettic-otc-cpt.php:458 +msgid "e.g., AICPA, BSI Group, Schellman" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:462 +msgid "Issue Date" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:467 includes/class-ettic-otc-cpt.php:1023 +#, fuzzy +msgid "Expiry Date" +msgstr "Vervaldatum" + +#: includes/class-ettic-otc-cpt.php:472 +msgid "Framework Logo" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:477 +msgid "" +"Use the official framework mark where licensing allows (SOC 2, ISO, GDPR " +"shield). Square images work best at 44×44." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:481 +msgid "Proof Artifact" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:484 includes/class-ettic-otc-cpt.php:631 +msgid "View file" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:489 +msgid "" +"Optional PDF the trust center can link to — e.g. the audit report, " +"certificate, or policy mapping document. Shown as a download button on the " +"card." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:493 +msgid "Scope & Notes" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:494 +msgid "" +"e.g., We process EU personal data under GDPR. Our DPA covers customer data, " +"and we support DSARs within 30 days." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:495 +msgid "" +"Required for self-attested frameworks so the card has meaningful content. " +"One or two sentences on scope, how you meet the framework, or what prospects " +"should know." +msgstr "" + +#. translators: %s: policy version number +#: includes/class-ettic-otc-cpt.php:550 +#, fuzzy, php-format +msgid "Version %s" +msgstr "Versie %s" + +#: includes/class-ettic-otc-cpt.php:553 +msgid "" +"Regular saves update the current version. Use the checkbox below to formally " +"publish a new version." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:562 +msgid "Publish as new version" +msgstr "" + +#. translators: %1$d: current version number, %2$d: next version number +#: includes/class-ettic-otc-cpt.php:567 +#, php-format +msgid "" +"This will save the current content as v%1$d and create v%2$d. Only check " +"this for formal, published changes — not minor edits." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:576 +msgid "What changed?" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:579 +msgid "e.g., Updated data retention from 90 to 60 days" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:580 +msgid "Shown in the public version history." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:586 +msgid "Policy ID" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:587 +msgid "e.g., POL-012" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:588 +msgid "" +"Optional short reference (e.g., POL-012). Shown on the public listing and in " +"security questionnaires." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:592 includes/class-ettic-otc-cpt.php:1061 +#: templates/partials/policies.php:55 +#, fuzzy +msgid "Category" +msgstr "Categorie" + +#: includes/class-ettic-otc-cpt.php:601 +msgid "Effective Date" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:606 +msgid "Next Review Date" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:611 +msgid "Framework Citations" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:622 +msgid "e.g., SOC 2 CC6.1, ISO 27001 A.9.2…" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:624 +msgid "" +"Framework or control references this policy satisfies. Appears as pill " +"badges on the public page." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:628 +msgid "PDF Attachment" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:634 +msgid "Replace PDF" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:634 +msgid "Upload PDF" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:636 +msgid "" +"Upload the signed PDF. Visitors see a \"Download PDF\" button only when a " +"file is attached." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:640 includes/class-ettic-otc-cpt.php:796 +msgid "Sort Order" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:642 includes/class-ettic-otc-cpt.php:798 +msgid "Lower numbers appear first." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:659 includes/class-ettic-otc-cpt.php:730 +#: includes/class-ettic-otc-cpt.php:1092 +#: templates/partials/data-practices.php:96 +#: templates/partials/subprocessors.php:37 +#, fuzzy +msgid "Purpose" +msgstr "Doel" + +#: includes/class-ettic-otc-cpt.php:661 +msgid "What does this subprocessor do for your company?" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:665 templates/partials/subprocessors.php:38 +#, fuzzy +msgid "Data Processed" +msgstr "Verwerkte gegevens" + +#: includes/class-ettic-otc-cpt.php:667 +msgid "What types of data does this subprocessor handle?" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:671 +msgid "Country / Location" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:672 +msgid "e.g., United States" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:676 templates/partials/subprocessors.php:41 +#, fuzzy +msgid "Website" +msgstr "Website" + +#: includes/class-ettic-otc-cpt.php:683 +#, fuzzy +msgid "DPA Signed" +msgstr "DPA ondertekend" + +#: includes/class-ettic-otc-cpt.php:685 +msgid "" +"A Data Processing Agreement (DPA) is a contract between you and the " +"subprocessor covering how they handle personal data on your behalf. Check " +"this box once your organization has signed one with this vendor." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:715 +msgid "Data Items Collected" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:724 includes/class-ettic-otc-cpt.php:762 +msgid "Type and press Enter..." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:737 +#: templates/partials/data-practices.php:103 +#, fuzzy +msgid "Legal Basis" +msgstr "Wettelijke grondslag" + +#: includes/class-ettic-otc-cpt.php:739 +msgid "— Select —" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:746 +msgid "Retention Period" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:747 +msgid "e.g., 30 days" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:753 +#: templates/partials/data-practices.php:117 +#, fuzzy +msgid "Shared With" +msgstr "Gedeeld met" + +#: includes/class-ettic-otc-cpt.php:768 +msgid "Properties" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:772 +msgid "Collected" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:776 +msgid "Stored" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:780 +msgid "Shared with third parties" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:784 +msgid "Sold to third parties" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:788 +msgid "Encrypted" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:791 +msgid "" +"Unchecked means an explicit \"No\". The AI assistant reports these values " +"verbatim to visitors asking questions like \"Do you sell customer data?\"." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:1060 templates/partials/policies.php:52 +msgid "ID" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:1062 +#: includes/class-ettic-otc-version.php:160 templates/partials/policies.php:56 +#, fuzzy +msgid "Version" +msgstr "Versie" + +#: includes/class-ettic-otc-cpt.php:1063 +msgid "PDF" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:1093 +#: templates/partials/subprocessors.php:39 +#, fuzzy +msgid "Location" +msgstr "Locatie" + +#: includes/class-ettic-otc-cpt.php:1094 +#: templates/partials/subprocessors.php:40 +#, fuzzy +msgid "DPA" +msgstr "DPA" + +#: includes/class-ettic-otc-cpt.php:1113 +#, fuzzy +msgid "Data Items" +msgstr "Gegevensitems" + +#: includes/class-ettic-otc-cpt.php:1114 includes/class-ettic-otc-cpt.php:1183 +msgid "Order" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:1143 +msgid "Related Policy" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:1145 +msgid "— None —" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:1150 +msgid "Optional — link this answer to a published policy for deeper context." +msgstr "" + +#: includes/class-ettic-otc-cpt.php:1155 +msgid "Sort order:" +msgstr "" + +#: includes/class-ettic-otc-cpt.php:1156 +msgid "" +"Use the Page Attributes box below (Order field) to control FAQ order. Lower " +"numbers appear first." +msgstr "" + +#: includes/class-ettic-otc-io.php:193 +msgid "PHP ZipArchive extension is required for export." +msgstr "" + +#: includes/class-ettic-otc-io.php:198 +msgid "Could not create temp file for export." +msgstr "" + +#: includes/class-ettic-otc-io.php:212 +msgid "Could not open ZIP for writing." +msgstr "" + +#: includes/class-ettic-otc-io.php:240 +msgid "Unrecognised export format." +msgstr "" + +#. translators: %1$d: schema version found, %2$d: schema version expected +#: includes/class-ettic-otc-io.php:246 +#, php-format +msgid "Schema version mismatch (found %1$d, expected %2$d)." +msgstr "" + +#. translators: %1$s: their version, %2$s: our version +#: includes/class-ettic-otc-io.php:257 +#, php-format +msgid "Plugin major version mismatch (export: %1$s, this site: %2$s)." +msgstr "" + +#: includes/class-ettic-otc-io.php:396 +msgid "PHP ZipArchive extension is required." +msgstr "" + +#: includes/class-ettic-otc-io.php:400 +msgid "Could not open uploaded archive." +msgstr "" + +#: includes/class-ettic-otc-io.php:405 +msgid "Archive is missing manifest.json." +msgstr "" + +#: includes/class-ettic-otc-io.php:409 +msgid "manifest.json could not be parsed." +msgstr "" + +#: includes/class-ettic-otc-io.php:692 +msgid "Could not reopen archive for media import." +msgstr "" + +#. translators: %s: media path +#: includes/class-ettic-otc-io.php:707 +#, php-format +msgid "Bundled media missing during import: %s" +msgstr "" + +#. translators: %s: filename +#: includes/class-ettic-otc-io.php:727 +#, php-format +msgid "Could not write attachment file: %s" +msgstr "" + +#: includes/class-ettic-otc-io.php:745 +msgid "Could not create attachment." +msgstr "" + +#: includes/class-ettic-otc-render.php:83 +msgid "Session expired. Please reload the page and try again." +msgstr "" + +#: includes/class-ettic-otc-render.php:89 +#, fuzzy +msgid "Please enter a question." +msgstr "Voer een vraag in." + +#: includes/class-ettic-otc-render.php:98 +msgid "AI chat is not configured." +msgstr "" + +#: includes/class-ettic-otc-render.php:270 +msgid "Page not found." +msgstr "" + +#: includes/class-ettic-otc-render.php:271 +#: templates/partials/policy-single.php:54 +#, fuzzy +msgid "Back to Trust Center" +msgstr "Terug naar Trust Center" + +#: includes/class-ettic-otc-render.php:442 +msgid "Updated just now" +msgstr "" + +#. translators: %d: number of minutes since last update +#: includes/class-ettic-otc-render.php:447 +#, fuzzy, php-format +msgid "Updated %d minute ago" +msgid_plural "Updated %d minutes ago" +msgstr[0] "%d minuut geleden bijgewerkt" +msgstr[1] "%d minuten geleden bijgewerkt" + +#. translators: %d: number of hours since last update +#: includes/class-ettic-otc-render.php:454 +#, fuzzy, php-format +msgid "Updated %d hour ago" +msgid_plural "Updated %d hours ago" +msgstr[0] "%d uur geleden bijgewerkt" +msgstr[1] "%d uur geleden bijgewerkt" + +#. translators: %d: number of days since last update +#: includes/class-ettic-otc-render.php:461 +#, fuzzy, php-format +msgid "Updated %d day ago" +msgid_plural "Updated %d days ago" +msgstr[0] "%d dag geleden bijgewerkt" +msgstr[1] "%d dagen geleden bijgewerkt" + +#. translators: %s = formatted date +#. translators: %s: policy last updated date +#: includes/class-ettic-otc-render.php:467 +#: templates/partials/policy-single.php:111 +#, fuzzy, php-format +msgid "Updated %s" +msgstr "Bijgewerkt op %s" + +#: includes/class-ettic-otc-render.php:511 +msgid "Security" +msgstr "" + +#: includes/class-ettic-otc-render.php:512 +msgid "Privacy" +msgstr "" + +#: includes/class-ettic-otc-render.php:513 +msgid "Compliance" +msgstr "" + +#: includes/class-ettic-otc-render.php:514 +msgid "Operational" +msgstr "" + +#: includes/class-ettic-otc-render.php:526 +msgid "Certified" +msgstr "" + +#: includes/class-ettic-otc-render.php:527 +msgid "In audit" +msgstr "" + +#: includes/class-ettic-otc-render.php:528 +#, fuzzy +msgid "Expired" +msgstr "Verlopen" + +#: includes/class-ettic-otc-render.php:537 +#, fuzzy +msgid "Compliant" +msgstr "Compliant" + +#: includes/class-ettic-otc-render.php:538 +msgid "Working toward" +msgstr "" + +#: includes/class-ettic-otc-render.php:539 +msgid "Lapsed" +msgstr "" + +#: includes/class-ettic-otc-render.php:545 +msgid "Consent" +msgstr "" + +#: includes/class-ettic-otc-render.php:546 +msgid "Contractual Necessity" +msgstr "" + +#: includes/class-ettic-otc-render.php:547 +msgid "Legitimate Interest" +msgstr "" + +#: includes/class-ettic-otc-render.php:548 +msgid "Legal Obligation" +msgstr "" + +#: includes/class-ettic-otc-render.php:549 +msgid "Vital Interest" +msgstr "" + +#: includes/class-ettic-otc-render.php:550 +msgid "Public Interest" +msgstr "" + +#: includes/class-ettic-otc-version.php:127 +msgid "Version History" +msgstr "" + +#: includes/class-ettic-otc-version.php:149 +msgid "Current version:" +msgstr "" + +#: includes/class-ettic-otc-version.php:152 +msgid "Version history will appear after the first update." +msgstr "" + +#: includes/class-ettic-otc-version.php:162 templates/partials/policies.php:58 +#, fuzzy +msgid "Actions" +msgstr "Acties" + +#: includes/class-ettic-otc-version.php:169 +#: templates/partials/policy-single.php:174 +msgid "Current" +msgstr "" + +#: includes/class-ettic-otc-version.php:183 +#: includes/class-ettic-otc-version.php:184 +msgid "View" +msgstr "" + +#: includes/class-ettic-otc-version.php:187 +msgid "Compare" +msgstr "" + +#: includes/class-ettic-otc-version.php:188 +msgid "Diff" +msgstr "" + +#: includes/data/faq-catalog.php:29 +msgid "What is a trust center?" +msgstr "" + +#: includes/data/faq-catalog.php:30 +msgid "" +"A trust center is a public page where a company shares information about how " +"it handles security, privacy, and compliance. It usually includes security " +"policies, a list of subprocessors, compliance certifications, and details " +"about how customer data is handled. The goal is to give customers, partners, " +"and prospects one place to answer due diligence questions without having to " +"email anyone." +msgstr "" + +#: includes/data/faq-catalog.php:34 +msgid "What is a Data Processing Agreement (DPA)?" +msgstr "" + +#: includes/data/faq-catalog.php:35 +msgid "" +"A Data Processing Agreement, or DPA, is a contract between a company that " +"collects personal data and a company that processes that data on its behalf. " +"It defines what data can be processed, for what purpose, how long it can be " +"kept, and what security measures must be in place. Under privacy laws like " +"the GDPR, a DPA is required whenever one company processes personal data for " +"another." +msgstr "" + +#: includes/data/faq-catalog.php:39 +msgid "What is a subprocessor?" +msgstr "" + +#: includes/data/faq-catalog.php:40 +msgid "" +"A subprocessor is a third-party service that a company uses to help deliver " +"its product, and that may come into contact with customer data along the " +"way. Common examples include cloud hosting providers, email delivery " +"services, analytics platforms, and customer support tools. Companies publish " +"subprocessor lists so customers can see exactly which vendors may handle " +"their data." +msgstr "" + +#: includes/data/faq-catalog.php:44 +msgid "What is the difference between a data controller and a data processor?" +msgstr "" + +#: includes/data/faq-catalog.php:45 +msgid "" +"The data controller is the party that decides why and how personal data is " +"collected and used. The data processor is the party that handles that data " +"on the controller's behalf, following the controller's instructions. A SaaS " +"customer is usually the controller of their end-user data, while the SaaS " +"vendor acts as the processor. Each role carries different legal " +"responsibilities under privacy laws like the GDPR." +msgstr "" + +#: includes/data/faq-catalog.php:49 +msgid "What is personal data?" +msgstr "" + +#: includes/data/faq-catalog.php:50 +msgid "" +"Personal data is any information that can be used to identify a living " +"person, either on its own or when combined with other information. Obvious " +"examples include names, email addresses, phone numbers, and home addresses. " +"Less obvious examples include IP addresses, device identifiers, cookies, and " +"location data. Privacy laws such as the GDPR and CCPA treat personal data as " +"something that must be collected, stored, and shared with care." +msgstr "" + +#: includes/data/faq-catalog.php:54 +msgid "What is responsible disclosure?" +msgstr "" + +#: includes/data/faq-catalog.php:55 +msgid "" +"Responsible disclosure is the practice of reporting a security vulnerability " +"privately to the company that owns the affected system, giving them a " +"reasonable amount of time to fix it before any details are shared publicly. " +"It protects users from being exposed to a known issue before a patch is " +"available. Most trust centers include a contact address or form for " +"reporting vulnerabilities this way." +msgstr "" + +#: includes/data/faq-catalog.php:59 +msgid "What is a compliance certification?" +msgstr "" + +#: includes/data/faq-catalog.php:60 +msgid "" +"A compliance certification is a formal statement, usually issued by an " +"independent auditor, confirming that a company meets the requirements of a " +"specific security or privacy standard. Certifications give customers a way " +"to trust a company's practices without having to inspect them directly. The " +"scope, issuing body, and validity period are typically listed alongside each " +"certification in a trust center." +msgstr "" + +#: includes/data/faq-catalog.php:64 +msgid "What is a security policy?" +msgstr "" + +#: includes/data/faq-catalog.php:65 +msgid "" +"A security policy is a written document that describes how a company " +"protects its systems, data, and people. Policies commonly cover topics like " +"access control, incident response, acceptable use, vendor management, and " +"business continuity. Publishing policies in a trust center lets customers " +"see how security is handled without needing to sign an NDA first." +msgstr "" + +#: includes/data/faq-catalog.php:69 +msgid "Why do companies publish a list of subprocessors?" +msgstr "" + +#: includes/data/faq-catalog.php:70 +msgid "" +"Publishing a subprocessor list is a transparency practice, and in many cases " +"a legal requirement, that lets customers see every third party that may " +"handle their data. It gives customers the chance to review new vendors " +"before they start processing data, and it makes it easier to meet their own " +"compliance obligations. Most trust centers also offer a way to be notified " +"when the list changes." +msgstr "" + +#: includes/data/faq-catalog.php:74 +msgid "What is a data practice?" +msgstr "" + +#: includes/data/faq-catalog.php:75 +msgid "" +"A data practice describes a specific way a company collects, uses, stores, " +"or shares information. Each practice usually spells out what data is " +"involved, why it is collected, how long it is kept, and who it is shared " +"with. Grouping data practices by category, such as account data, usage data, " +"or support data, helps customers understand exactly what happens to their " +"information." +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider-anthropic.php:44 +#: includes/providers/class-ettic-otc-chat-provider.php:46 +msgid "Anthropic" +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider-anthropic.php:63 +msgid "No models available — your account may not be authorized." +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider-anthropic.php:127 +msgid "Anthropic adapter missing required args." +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider-anthropic.php:219 +msgid "Anthropic request failed." +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider-anthropic.php:414 +msgid "Searching documents…" +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider-anthropic.php:415 +msgid "Reading documents…" +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider-openai.php:66 +#: includes/providers/class-ettic-otc-chat-provider.php:52 +msgid "OpenAI" +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider-openai.php:166 +msgid "OpenAI adapter missing required args." +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider-openai.php:253 +msgid "OpenAI request failed." +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider-openrouter.php:38 +#: includes/providers/class-ettic-otc-chat-provider.php:58 +msgid "OpenRouter" +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider.php:104 +msgid "No chat models available for this key." +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider.php:117 +msgid "API key is empty." +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider.php:123 +msgid "Request failed." +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider.php:268 +msgid "" +"I couldn't find a confident answer in the published trust center documents. " +"Please contact the team for help." +msgstr "" + +#. translators: %s is the document title. +#: includes/providers/class-ettic-otc-chat-provider.php:342 +#, php-format +msgid "Read \"%s\"" +msgstr "" + +#. translators: %s is the document title. +#: includes/providers/class-ettic-otc-chat-provider.php:344 +#, php-format +msgid "Reading \"%s\"" +msgstr "" + +#. translators: %s is the document id. +#: includes/providers/class-ettic-otc-chat-provider.php:350 +#, php-format +msgid "Read %s" +msgstr "" + +#. translators: %s is the document id. +#: includes/providers/class-ettic-otc-chat-provider.php:352 +#, php-format +msgid "Reading %s" +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider.php:354 +msgid "Read a document" +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider.php:354 +msgid "Reading a document" +msgstr "" + +#. translators: %s is the search query. +#: includes/providers/class-ettic-otc-chat-provider.php:367 +#, php-format +msgid "Searched for \"%s\"" +msgstr "" + +#. translators: %s is the search query. +#: includes/providers/class-ettic-otc-chat-provider.php:369 +#, php-format +msgid "Searching for \"%s\"" +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider.php:371 +msgid "Searched documents" +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider.php:371 +msgid "Searching documents" +msgstr "" + +#. translators: %d is the number of documents that were read in parallel. +#: includes/providers/class-ettic-otc-chat-provider.php:399 +#, php-format +msgid "Read %d documents" +msgstr "" + +#. translators: %d is the number of documents being read in parallel. +#: includes/providers/class-ettic-otc-chat-provider.php:401 +#, php-format +msgid "Reading %d documents" +msgstr "" + +#. translators: %d is the number of search queries that were fired in parallel. +#: includes/providers/class-ettic-otc-chat-provider.php:406 +#, php-format +msgid "Ran %d searches" +msgstr "" + +#. translators: %d is the number of search queries fired in parallel. +#: includes/providers/class-ettic-otc-chat-provider.php:408 +#, php-format +msgid "Running %d searches" +msgstr "" + +#. translators: %d is the number of parallel retrieval calls (mixed types). +#: includes/providers/class-ettic-otc-chat-provider.php:412 +#, php-format +msgid "Ran %d retrievals" +msgstr "" + +#. translators: %d is the number of parallel retrieval calls (mixed types). +#: includes/providers/class-ettic-otc-chat-provider.php:414 +#, php-format +msgid "Running %d retrievals" +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider.php:443 +#: includes/providers/class-ettic-otc-chat-provider.php:462 +#: includes/providers/class-ettic-otc-chat-provider.php:513 +msgid "Refused outbound request to disallowed host." +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider.php:518 +msgid "AI streaming requires the PHP cURL extension." +msgstr "" + +#: includes/providers/class-ettic-otc-chat-provider.php:620 +msgid "AI streaming requires the WordPress cURL transport." +msgstr "" + +#. translators: %d: HTTP status code returned by the provider +#: includes/providers/class-ettic-otc-chat-provider.php:673 +#: includes/providers/class-ettic-otc-chat-provider.php:728 +#, php-format +msgid "Provider returned HTTP %d" +msgstr "" + +#. translators: %s: company name +#: templates/chat.php:70 +#, fuzzy, php-format +msgid "Ask %s — Trust Center" +msgstr "Vraag het aan %s — Trust Center" + +#: templates/chat.php:100 templates/trust-center.php:101 +msgid "Skip to content" +msgstr "" + +#: templates/chat.php:102 templates/partials/policy-single.php:36 +#: templates/trust-center.php:114 +msgid "Trust center navigation" +msgstr "" + +#: templates/chat.php:131 templates/trust-center.php:144 +#, fuzzy +msgid "Ask AI" +msgstr "Vraag de AI" + +#: templates/chat.php:145 +msgid "Ask AI is not configured" +msgstr "" + +#: templates/chat.php:146 +msgid "The site administrator has not enabled the AI chat feature yet." +msgstr "" + +#: templates/chat.php:148 +msgid "Browse trust center" +msgstr "" + +#: templates/chat.php:176 templates/chat.php:353 +#, fuzzy +msgid "You" +msgstr "Jij" + +#: templates/chat.php:178 templates/chat.php:195 templates/chat.php:354 +#, fuzzy +msgid "just now" +msgstr "zojuist" + +#: templates/chat.php:202 templates/chat.php:346 +#, fuzzy +msgid "Sources" +msgstr "Bronnen" + +#: templates/chat.php:212 templates/chat.php:356 +#, fuzzy +msgid "" +"AI-generated answer. Not legal, security, or compliance advice. Verify " +"against the sources above." +msgstr "" +"Dit antwoord is door AI gegenereerd. Geen juridisch, beveiligings- of " +"compliance-advies. Controleer het altijd aan de hand van de bronnen " +"hierboven." + +#: templates/chat.php:222 +msgid "" +"JavaScript is disabled — you can still ask one question below. The answer " +"will load as a regular page." +msgstr "" + +#: templates/chat.php:225 +msgid "Your question" +msgstr "" + +#: templates/chat.php:232 +msgid "Ask" +msgstr "" + +#: templates/chat.php:243 +#, fuzzy +msgid "Are you SOC 2 compliant?" +msgstr "Zijn jullie SOC 2-compliant?" + +#: templates/chat.php:244 +#, fuzzy +msgid "Where is customer data stored?" +msgstr "Waar worden klantgegevens opgeslagen?" + +#: templates/chat.php:245 +msgid "What's your incident response process?" +msgstr "" + +#: templates/chat.php:246 +#, fuzzy +msgid "Which subprocessors do you use?" +msgstr "Welke subverwerkers gebruiken jullie?" + +#: templates/chat.php:271 +msgid "Suggested questions" +msgstr "" + +#: templates/chat.php:286 +msgid "Ask a question" +msgstr "" + +#: templates/chat.php:293 templates/chat.php:335 +#, fuzzy +msgid "Ask anything about our security and compliance…" +msgstr "Stel een vraag over onze beveiliging en compliance…" + +#: templates/chat.php:295 templates/chat.php:344 +#, fuzzy +msgid "Start a new conversation" +msgstr "Start een nieuw gesprek" + +#: templates/chat.php:298 templates/chat.php:336 +#, fuzzy +msgid "Send" +msgstr "Versturen" + +#. translators: 1: link to trust center, 2: company name +#: templates/chat.php:309 +#, php-format +msgid "" +"Grounded in the published %1$s for %2$s. AI-generated, not legal, security, " +"or compliance advice. Always check the sources." +msgstr "" + +#: templates/chat.php:310 +msgid "trust center" +msgstr "" + +#: templates/chat.php:337 +#, fuzzy +msgid "Stop" +msgstr "Stoppen" + +#: templates/chat.php:338 +#, fuzzy +msgid "Thinking…" +msgstr "Denkt na…" + +#: templates/chat.php:339 +#, fuzzy +msgid "Connection lost. Retry?" +msgstr "Verbinding verbroken. Opnieuw proberen?" + +#: templates/chat.php:340 +#, fuzzy +msgid "Contact security team →" +msgstr "Neem contact op met het beveiligingsteam →" + +#: templates/chat.php:341 +#, fuzzy +msgid "Copy" +msgstr "Kopiëren" + +#: templates/chat.php:342 +#, fuzzy +msgid "Copied" +msgstr "Gekopieerd" + +#: templates/chat.php:343 templates/partials/policy-single.php:139 +#, fuzzy +msgid "Print" +msgstr "Afdrukken" + +#: templates/chat.php:345 +#, fuzzy +msgid "This conversation is getting long. Start fresh for better answers." +msgstr "Dit gesprek wordt lang — begin opnieuw voor de beste antwoorden." + +#: templates/chat.php:347 +#, fuzzy +msgid "" +"I don't see enough information in our trust center to answer that " +"confidently." +msgstr "" +"In ons Trust Center staat niet genoeg informatie om die vraag met zekerheid " +"te beantwoorden." + +#: templates/chat.php:348 +#, fuzzy +msgid "The AI provider returned an error. Please try again." +msgstr "De AI-provider gaf een fout. Probeer het opnieuw." + +#: templates/chat.php:349 +#, fuzzy +msgid "" +"AI is temporarily unavailable. Please try again in a few minutes or browse " +"our published content." +msgstr "" +"De AI is tijdelijk niet beschikbaar. Probeer het over enkele minuten opnieuw " +"of bekijk onze gepubliceerde content." + +#: templates/chat.php:350 +#, fuzzy +msgid "Message is too long." +msgstr "Het bericht is te lang." + +#: templates/chat.php:351 +#, fuzzy +msgid "Please wait a moment before asking again." +msgstr "Wacht even voordat je opnieuw een vraag stelt." + +#: templates/chat.php:352 +#, fuzzy +msgid "Cite source" +msgstr "Bron citeren" + +#: templates/chat.php:355 +#, fuzzy +msgid "No content returned by the model." +msgstr "Het model gaf geen antwoord terug." + +#: templates/partials/certifications.php:23 +#, fuzzy +msgid "" +"Our active certifications and compliance frameworks demonstrate our " +"commitment to protecting your data." +msgstr "" +"Onze actieve certificeringen en compliance-frameworks laten zien hoe serieus " +"we jouw gegevens beschermen." + +#: templates/partials/certifications.php:59 +msgid "Self-attested framework" +msgstr "" + +#. translators: %s: certification issue date +#: templates/partials/certifications.php:98 +#, fuzzy, php-format +msgid "Issued %s" +msgstr "Uitgegeven op %s" + +#. translators: %s: certification expiry date +#: templates/partials/certifications.php:102 +#, fuzzy, php-format +msgid "Expires %s" +msgstr "Verloopt op %s" + +#: templates/partials/certifications.php:114 +msgid "Download report" +msgstr "" + +#: templates/partials/certifications.php:115 +msgid "View documentation" +msgstr "" + +#: templates/partials/chat-budget-exhausted.php:18 +msgid "Ask AI is taking a breather" +msgstr "" + +#: templates/partials/chat-budget-exhausted.php:19 +msgid "" +"We've hit the daily question limit. Chat will be back soon — in the " +"meantime, you can still browse the full trust center." +msgstr "" + +#: templates/partials/chat-budget-exhausted.php:22 +msgid "Browse policies" +msgstr "" + +#: templates/partials/chat-budget-exhausted.php:29 +msgid "Contact us" +msgstr "" + +#. translators: %s: company name +#: templates/partials/chat-empty-state.php:29 +#, fuzzy, php-format +msgid "Ask about %s's security and compliance" +msgstr "Vraag ons over de beveiliging en compliance van %s" + +#. translators: 1: model identifier, 2: sources summary +#: templates/partials/chat-empty-state.php:37 +#, php-format +msgid "Using model %1$s. Grounded in %2$s." +msgstr "" + +#. translators: %s: sources summary +#: templates/partials/chat-empty-state.php:49 +#, fuzzy, php-format +msgid "Grounded in %s." +msgstr "Gebaseerd op %s." + +#: templates/partials/chat-empty-state.php:60 +msgid "Conversation" +msgstr "" + +#: templates/partials/contact.php:41 +msgid "Data Protection Officer" +msgstr "" + +#: templates/partials/contact.php:48 +msgid "Security Team" +msgstr "" + +#: templates/partials/contact.php:57 +msgid "Contact Form" +msgstr "" + +#: templates/partials/contact.php:59 +msgid "Open the contact form" +msgstr "" + +#: templates/partials/contact.php:66 +msgid "PGP Public Key" +msgstr "" + +#: templates/partials/contact.php:68 +msgid "Download public key" +msgstr "" + +#: templates/partials/contact.php:91 +msgid "Company Registration" +msgstr "" + +#: templates/partials/data-practices.php:35 +#, fuzzy +msgid "What we collect and how we handle your data." +msgstr "Welke gegevens we verzamelen en hoe we ze gebruiken." + +#. translators: %1$d = number, %2$s = category name +#: templates/partials/data-practices.php:73 +#, fuzzy, php-format +msgid "View %1$d more %2$s items" +msgstr "Bekijk nog %1$d %2$s-items" + +#: templates/partials/data-practices.php:110 +#, fuzzy +msgid "Retention" +msgstr "Bewaartermijn" + +#: templates/partials/faq.php:42 +msgid "Frequently Asked Questions" +msgstr "" + +#: templates/partials/faq.php:43 +msgid "Quick answers to the questions we hear most." +msgstr "" + +#: templates/partials/faq.php:57 +msgid "Related:" +msgstr "" + +#. translators: %d: number of active certifications +#: templates/partials/hero.php:31 +#, fuzzy, php-format +msgid "%d Active Certification" +msgid_plural "%d Active Certifications" +msgstr[0] "%d Actieve certificering" +msgstr[1] "%d Actieve certificeringen" + +#: templates/partials/hero.php:38 templates/trust-center.php:19 +#, fuzzy +msgid "Trust Center" +msgstr "Trust Center" + +#: templates/partials/policies.php:27 +#, fuzzy +msgid "Security Policies" +msgstr "Beveiligingsbeleid" + +#: templates/partials/policies.php:28 +#, fuzzy +msgid "" +"Our published security and compliance policies are regularly reviewed and " +"updated." +msgstr "" +"Ons gepubliceerde beveiligings- en compliancebeleid wordt regelmatig herzien " +"en bijgewerkt." + +#: templates/partials/policies.php:57 +#, fuzzy +msgid "Last Updated" +msgstr "Laatst bijgewerkt" + +#: templates/partials/policies.php:89 templates/partials/policy-single.php:116 +msgid "Framework citations" +msgstr "" + +#. translators: %s: policy version number +#: templates/partials/policies.php:99 templates/partials/policy-single.php:94 +#, fuzzy, php-format +msgid "v%s" +msgstr "v%s" + +#. translators: %s: human-readable file size +#: templates/partials/policies.php:106 templates/partials/policy-single.php:130 +#, php-format +msgid "Download PDF (%s)" +msgstr "" + +#: templates/partials/policies.php:108 templates/partials/policy-single.php:132 +#, fuzzy +msgid "Download PDF" +msgstr "Download PDF" + +#. translators: %s: policy title +#: templates/partials/policies.php:116 +#, fuzzy, php-format +msgid "View %s" +msgstr "%s bekijken" + +#. translators: %1$s: version number, %2$s: link to current version +#: templates/partials/policy-single.php:63 +#, fuzzy, php-format +msgid "You are viewing version %1$s. %2$s" +msgstr "Je bekijkt versie %1$s. %2$s" + +#: templates/partials/policy-single.php:65 +#: templates/partials/policy-single.php:78 +#, fuzzy +msgid "View current version" +msgstr "Huidige versie bekijken" + +#. translators: %1$s: effective date, %2$s: link to previous version +#: templates/partials/policy-single.php:75 +#, fuzzy, php-format +msgid "This version takes effect on %1$s. %2$s" +msgstr "Deze versie gaat in op %1$s. %2$s" + +#. translators: %s: policy effective date +#: templates/partials/policy-single.php:105 +#, php-format +msgid "Effective %s" +msgstr "" + +#. translators: %d: number of policy versions +#: templates/partials/policy-single.php:150 +#, fuzzy, php-format +msgid "Version history (%d)" +msgstr "Versiegeschiedenis (%d)" + +#. translators: %d: version number +#: templates/partials/policy-single.php:166 +#, fuzzy, php-format +msgid "v%d" +msgstr "v%d" + +#: templates/partials/subprocessors.php:21 +#, fuzzy +msgid "" +"Third-party services that process data on our behalf, along with their " +"purposes and data handling agreements." +msgstr "" +"Externe diensten die namens ons gegevens verwerken, met hun doel en " +"verwerkersovereenkomsten." + +#: templates/partials/subprocessors.php:36 +#, fuzzy +msgid "Name" +msgstr "Naam" + +#: templates/partials/subprocessors.php:53 +#: templates/partials/subprocessors.php:57 +#, fuzzy +msgid "more" +msgstr "meer" + +#: templates/partials/subprocessors.php:64 +#, fuzzy +msgid "Signed" +msgstr "Ondertekend" + +#: templates/trust-center.php:21 +#, fuzzy +msgid "Transparency and security you can trust." +msgstr "Transparante beveiliging om op te vertrouwen." + +#: templates/trust-center.php:196 +msgid "Trust center content is being prepared. Check back soon." +msgstr "" + +#. translators: %s: company name +#: templates/trust-center.php:212 +#, fuzzy, php-format +msgid "© %1$s %2$s. All rights reserved." +msgstr "© %1$s %2$s. Alle rechten voorbehouden." + +#: templates/trust-center.php:220 +msgid "Powered by Open Trust Center" +msgstr "" + +#, fuzzy +#~ msgid "OpenTrust" +#~ msgstr "OpenTrust" + +#, fuzzy +#~ msgid "Email" +#~ msgstr "E-mail" + +#, fuzzy +#~ msgid "Company" +#~ msgstr "Bedrijf" + +#, fuzzy +#~ msgid "Active" +#~ msgstr "Actief" + +#, fuzzy +#~ msgid "In Progress" +#~ msgstr "In aanvraag" + +#, fuzzy +#~ msgid "Please enter a valid email address." +#~ msgstr "Voer een geldig e-mailadres in." + +#, fuzzy +#~ msgid "Please check your inbox and click the confirmation link." +#~ msgstr "Controleer je inbox en klik op de bevestigingslink." + +#, fuzzy, php-format +#~ msgid "Hi %s," +#~ msgstr "Hoi %s," + +#, fuzzy, php-format +#~ msgid "[%1$s] Policy updated: %2$s" +#~ msgstr "[%1$s] Beleid bijgewerkt: %2$s" + +#, fuzzy, php-format +#~ msgid "Confirm your subscription to %s Trust Center updates" +#~ msgstr "Bevestig je aanmelding voor Trust Center-updates van %s" + +#, fuzzy +#~ msgid "Invalid request." +#~ msgstr "Ongeldig verzoek." + +#, fuzzy +#~ msgid "Please complete the security check." +#~ msgstr "Voltooi de beveiligingscontrole." + +#, fuzzy +#~ msgid "Please select at least one category." +#~ msgstr "Selecteer ten minste één categorie." + +#, fuzzy +#~ msgid "Share" +#~ msgstr "Delen" + +#, fuzzy +#~ msgid "Link copied" +#~ msgstr "Link gekopieerd" + +#, fuzzy, php-format +#~ msgid "" +#~ "Thank you for subscribing to trust center updates from %s. Please confirm " +#~ "your subscription by clicking the button below." +#~ msgstr "" +#~ "Bedankt dat je je hebt aangemeld voor Trust Center-updates van %s. " +#~ "Bevestig je aanmelding door op de knop hieronder te klikken." + +#, fuzzy, php-format +#~ msgid "%1$s has updated the following policy on our trust center:" +#~ msgstr "%1$s heeft het volgende beleid bijgewerkt op het Trust Center:" + +#, fuzzy +#~ msgid "Unsubscribe" +#~ msgstr "Uitschrijven" + +#, fuzzy, php-format +#~ msgid "Powered by %1$s. Grounded in %2$s." +#~ msgstr "Mogelijk gemaakt door %1$s. Gebaseerd op %2$s." + +#, fuzzy, php-format +#~ msgid "Effective: %s" +#~ msgstr "Ingangsdatum: %s" + +#, fuzzy, php-format +#~ msgid "Updated: %s" +#~ msgstr "Bijgewerkt: %s" + +#, fuzzy +#~ msgid "Subscribe to updates" +#~ msgstr "Abonneer op updates" + +#, fuzzy, php-format +#~ msgid "Get email notifications when %s updates their trust center." +#~ msgstr "Ontvang e-mailmeldingen zodra %s hun Trust Center bijwerkt." + +#, fuzzy +#~ msgid "Email address" +#~ msgstr "E-mailadres" + +#, fuzzy +#~ msgid "Subscribe" +#~ msgstr "Abonneren" + +#, fuzzy, php-format +#~ msgid "Manage notifications for %s." +#~ msgstr "Beheer meldingen voor %s." diff --git a/languages/opentrust.pot b/languages/open-trust-center-by-ettic.pot similarity index 65% rename from languages/opentrust.pot rename to languages/open-trust-center-by-ettic.pot index fc091a9..ae1dfaa 100644 --- a/languages/opentrust.pot +++ b/languages/open-trust-center-by-ettic.pot @@ -2,777 +2,775 @@ # This file is distributed under the GPL-2.0-or-later. msgid "" msgstr "" -"Project-Id-Version: OpenTrust 1.1.1\n" -"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/opentrust\n" +"Project-Id-Version: Open Trust Center by Ettic 1.2.0\n" +"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/open-trust-center-by-ettic\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2026-05-14T14:04:32+00:00\n" +"POT-Creation-Date: 2026-05-17T12:29:04+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.12.0\n" -"X-Domain: opentrust\n" +"X-Domain: open-trust-center-by-ettic\n" #. Plugin Name of the plugin -#: opentrust.php -#: includes/class-opentrust-admin.php:56 -#: includes/class-opentrust-admin.php:57 -msgid "OpenTrust" +#: open-trust-center-by-ettic.php +msgid "Open Trust Center by Ettic" msgstr "" #. Plugin URI of the plugin -#: opentrust.php -msgid "https://plugins.ettic.nl/opentrust" +#: open-trust-center-by-ettic.php +msgid "https://plugins.ettic.nl/open-trust-center-by-ettic" msgstr "" #. Description of the plugin -#: opentrust.php +#: open-trust-center-by-ettic.php msgid "A self-hosted, open-source trust center for publishing security policies, subprocessors, certifications, and data practices." msgstr "" #. Author of the plugin -#: opentrust.php +#: open-trust-center-by-ettic.php msgid "Ettic" msgstr "" #. Author URI of the plugin -#: opentrust.php +#: open-trust-center-by-ettic.php msgid "https://plugins.ettic.nl" msgstr "" -#: includes/class-opentrust-admin-ai.php:78 +#: includes/class-ettic-otc-admin-ai.php:78 msgid "Heads up: citation fidelity is not guaranteed on your active provider." msgstr "" #. translators: %s: provider label, e.g. OpenAI -#: includes/class-opentrust-admin-ai.php:83 +#: includes/class-ettic-otc-admin-ai.php:83 #, php-format msgid "You are currently using %s. Only Anthropic uses a structural Citations API — every other provider relies on prompted citation tags the model can ignore or fabricate. For a published trust center, switch to Anthropic below." msgstr "" -#: includes/class-opentrust-admin-ai.php:94 -msgid "OpenTrust uses Anthropic Claude with the native Citations API to answer visitor questions about your trust center. Every claim the assistant makes is tied to an exact quote from one of your published documents — so no policy text is invented and nothing is paraphrased into something you did not actually publish." +#: includes/class-ettic-otc-admin-ai.php:94 +msgid "Ettic_OTC uses Anthropic Claude with the native Citations API to answer visitor questions about your trust center. Every claim the assistant makes is tied to an exact quote from one of your published documents — so no policy text is invented and nothing is paraphrased into something you did not actually publish." msgstr "" -#: includes/class-opentrust-admin-ai.php:101 +#: includes/class-ettic-otc-admin-ai.php:101 msgid "Why Anthropic, and not OpenAI or any other provider?" msgstr "" -#: includes/class-opentrust-admin-ai.php:106 +#: includes/class-ettic-otc-admin-ai.php:106 msgid "A trust center is a compliance surface. If the assistant invents a security commitment you never made, that is not a UX papercut — it is a misrepresentation of your security posture, and your customers and auditors will hold you to it." msgstr "" -#: includes/class-opentrust-admin-ai.php:114 +#: includes/class-ettic-otc-admin-ai.php:114 msgid "Anthropic is the only major provider that exposes a structural Citations API. Documents are sent as typed blocks and the model emits citations as first-class events containing the exact source document and the exact quoted text. The model literally cannot return a citation for text that is not in your source documents." msgstr "" -#: includes/class-opentrust-admin-ai.php:120 +#: includes/class-ettic-otc-admin-ai.php:120 msgid "Every other provider (including OpenAI and any model accessed via OpenRouter) relies on prompted citation tags that we parse out of the answer after the fact. That works most of the time, but the model can ignore the instructions, make up document IDs, or attach a citation to a sentence it actually hallucinated. We support these providers as an escape hatch for organizations that genuinely cannot use Anthropic for procurement or data-residency reasons — but we very, very strongly recommend you do not run a public trust center on them." msgstr "" #. translators: %d is the number of policies missing AI summaries. -#: includes/class-opentrust-admin-ai.php:159 +#: includes/class-ettic-otc-admin-ai.php:159 #, php-format msgid "%d policy is missing an AI summary." msgid_plural "%d policies are missing AI summaries." msgstr[0] "" msgstr[1] "" -#: includes/class-opentrust-admin-ai.php:170 +#: includes/class-ettic-otc-admin-ai.php:170 msgid "Generate them now so the assistant can route questions accurately." msgstr "" -#: includes/class-opentrust-admin-ai.php:175 +#: includes/class-ettic-otc-admin-ai.php:175 msgid "Generate now" msgstr "" -#: includes/class-opentrust-admin-ai.php:199 +#: includes/class-ettic-otc-admin-ai.php:199 msgid "Choose a provider and add your key" msgstr "" -#: includes/class-opentrust-admin-ai.php:211 +#: includes/class-ettic-otc-admin-ai.php:211 msgid "Step 1 — Connect Anthropic" msgstr "" -#: includes/class-opentrust-admin-ai.php:217 +#: includes/class-ettic-otc-admin-ai.php:217 msgid "Advanced: use a different provider (not recommended)" msgstr "" -#: includes/class-opentrust-admin-ai.php:220 +#: includes/class-ettic-otc-admin-ai.php:220 msgid "These providers cannot guarantee citation fidelity." msgstr "" -#: includes/class-opentrust-admin-ai.php:222 +#: includes/class-ettic-otc-admin-ai.php:222 msgid "OpenAI and OpenRouter rely on prompted [[cite:document-id]] tags that we parse out of the answer after generation. The model can ignore the instruction, invent document IDs, or attach a citation to a sentence it actually hallucinated. We cannot detect when this happens." msgstr "" -#: includes/class-opentrust-admin-ai.php:225 +#: includes/class-ettic-otc-admin-ai.php:225 msgid "Do not use these providers for a published trust center" msgstr "" -#: includes/class-opentrust-admin-ai.php:226 +#: includes/class-ettic-otc-admin-ai.php:226 msgid "unless your organization genuinely cannot use Anthropic for procurement, contractual, or data-residency reasons. Inaccurate claims about your security posture are a real compliance risk." msgstr "" -#: includes/class-opentrust-admin-ai.php:265 +#: includes/class-ettic-otc-admin-ai.php:265 msgid "Required for citation fidelity" msgstr "" -#: includes/class-opentrust-admin-ai.php:271 +#: includes/class-ettic-otc-admin-ai.php:271 msgid "Uses Claude with the native Citations API. Every quote the assistant attributes to one of your documents is structurally guaranteed to come from that document." msgstr "" #. translators: %s: provider name (e.g. Anthropic) -#: includes/class-opentrust-admin-ai.php:279 +#: includes/class-ettic-otc-admin-ai.php:279 #, php-format msgid "Get a %s API key" msgstr "" -#: includes/class-opentrust-admin-ai.php:292 +#: includes/class-ettic-otc-admin-ai.php:292 msgid "Remove the saved key for this provider?" msgstr "" -#: includes/class-opentrust-admin-ai.php:293 +#: includes/class-ettic-otc-admin-ai.php:293 msgid "Replace key" msgstr "" #. translators: %s: provider name (e.g. Anthropic) -#: includes/class-opentrust-admin-ai.php:303 +#: includes/class-ettic-otc-admin-ai.php:303 #, php-format msgid "Paste your %s API key…" msgstr "" -#: includes/class-opentrust-admin-ai.php:307 +#: includes/class-ettic-otc-admin-ai.php:307 msgid "Validate & save" msgstr "" -#: includes/class-opentrust-admin-ai.php:346 +#: includes/class-ettic-otc-admin-ai.php:346 msgid "Step 2 — Pick a model and tune defaults" msgstr "" -#: includes/class-opentrust-admin-ai.php:359 +#: includes/class-ettic-otc-admin-ai.php:359 msgid "Active model" msgstr "" -#: includes/class-opentrust-admin-ai.php:363 +#: includes/class-ettic-otc-admin-ai.php:363 msgid "No cached models found. Use Refresh to re-fetch the model list." msgstr "" -#: includes/class-opentrust-admin-ai.php:372 +#: includes/class-ettic-otc-admin-ai.php:372 msgid "(unavailable)" msgstr "" -#: includes/class-opentrust-admin-ai.php:376 +#: includes/class-ettic-otc-admin-ai.php:376 msgid "Recommended" msgstr "" -#: includes/class-opentrust-admin-ai.php:387 +#: includes/class-ettic-otc-admin-ai.php:387 msgid "Model unavailable" msgstr "" -#: includes/class-opentrust-admin-ai.php:392 +#: includes/class-ettic-otc-admin-ai.php:392 msgid "Refresh models" msgstr "" #. translators: %s: human-readable time difference (e.g. "5 minutes") -#: includes/class-opentrust-admin-ai.php:402 +#: includes/class-ettic-otc-admin-ai.php:402 #, php-format msgid "Model list cached %s ago." msgstr "" -#: includes/class-opentrust-admin-ai.php:410 +#: includes/class-ettic-otc-admin-ai.php:410 msgid "Daily token budget" msgstr "" -#: includes/class-opentrust-admin-ai.php:413 +#: includes/class-ettic-otc-admin-ai.php:413 msgid "Hard cap per site per day. Default 500,000 tokens (~$12/day at Sonnet 4.5 rates)." msgstr "" -#: includes/class-opentrust-admin-ai.php:417 +#: includes/class-ettic-otc-admin-ai.php:417 msgid "Monthly token budget" msgstr "" -#: includes/class-opentrust-admin-ai.php:420 +#: includes/class-ettic-otc-admin-ai.php:420 msgid "Hard cap per site per month. Default 10,000,000 tokens." msgstr "" -#: includes/class-opentrust-admin-ai.php:424 +#: includes/class-ettic-otc-admin-ai.php:424 msgid "Rate limit — per IP" msgstr "" -#: includes/class-opentrust-admin-ai.php:426 +#: includes/class-ettic-otc-admin-ai.php:426 msgid "messages per minute" msgstr "" -#: includes/class-opentrust-admin-ai.php:430 +#: includes/class-ettic-otc-admin-ai.php:430 msgid "Rate limit — per session" msgstr "" -#: includes/class-opentrust-admin-ai.php:432 +#: includes/class-ettic-otc-admin-ai.php:432 msgid "messages per hour" msgstr "" -#: includes/class-opentrust-admin-ai.php:436 +#: includes/class-ettic-otc-admin-ai.php:436 msgid "Max message length" msgstr "" -#: includes/class-opentrust-admin-ai.php:438 +#: includes/class-ettic-otc-admin-ai.php:438 msgid "characters" msgstr "" -#: includes/class-opentrust-admin-ai.php:443 +#: includes/class-ettic-otc-admin-ai.php:443 msgid "Refuse-to-answer contact URL" msgstr "" -#: includes/class-opentrust-admin-ai.php:446 +#: includes/class-ettic-otc-admin-ai.php:446 msgid "When the AI cannot confidently answer a question, it links here. Leave blank to use the trust center home." msgstr "" -#: includes/class-opentrust-admin-ai.php:451 +#: includes/class-ettic-otc-admin-ai.php:451 msgid "Visitor display" msgstr "" -#: includes/class-opentrust-admin-ai.php:455 +#: includes/class-ettic-otc-admin-ai.php:455 msgid "Show the active model name under the chat input" msgstr "" -#: includes/class-opentrust-admin-ai.php:461 +#: includes/class-ettic-otc-admin-ai.php:461 msgid "Analytics logging" msgstr "" -#: includes/class-opentrust-admin-ai.php:465 +#: includes/class-ettic-otc-admin-ai.php:465 msgid "Log anonymized visitor questions for admin review (90-day auto-purge, no PII)" msgstr "" -#: includes/class-opentrust-admin-ai.php:471 +#: includes/class-ettic-otc-admin-ai.php:471 msgid "Improve answer quality" msgstr "" -#: includes/class-opentrust-admin-ai.php:475 +#: includes/class-ettic-otc-admin-ai.php:475 msgid "Generate AI summaries of each policy" msgstr "" -#: includes/class-opentrust-admin-ai.php:478 +#: includes/class-ettic-otc-admin-ai.php:478 msgid "When on, the AI generates a 2–3 sentence summary of each published policy and stores it for routing decisions. Improves answers on questions like \"What's your data deletion policy?\" that don't match a title literally. Cost is roughly $0.05–$0.10 per 50 policies, lifetime — pennies per edit afterward. Uses your configured AI key." msgstr "" -#: includes/class-opentrust-admin-ai.php:487 +#: includes/class-ettic-otc-admin-ai.php:487 msgid "Oversized policies" msgstr "" -#: includes/class-opentrust-admin-ai.php:491 +#: includes/class-ettic-otc-admin-ai.php:491 msgid "The following policies are large enough that the AI will receive only a truncated version when retrieving them. Consider splitting them into shorter documents:" msgstr "" #. translators: 1: policy title, 2: token count. -#: includes/class-opentrust-admin-ai.php:498 +#: includes/class-ettic-otc-admin-ai.php:498 #, php-format msgid "%1$s (~%2$s tokens)" msgstr "" -#: includes/class-opentrust-admin-ai.php:512 +#: includes/class-ettic-otc-admin-ai.php:512 msgid "Advanced — Turnstile anti-abuse" msgstr "" -#: includes/class-opentrust-admin-ai.php:514 +#: includes/class-ettic-otc-admin-ai.php:514 msgid "Cloudflare Turnstile is optional but recommended for public sites. It challenges suspicious visitors on the first message of each session. You need a free Cloudflare account to get site/secret keys." msgstr "" -#: includes/class-opentrust-admin-ai.php:518 +#: includes/class-ettic-otc-admin-ai.php:518 msgid "Enable Turnstile for chat" msgstr "" -#: includes/class-opentrust-admin-ai.php:522 +#: includes/class-ettic-otc-admin-ai.php:522 msgid "Require Turnstile verification on first chat message" msgstr "" -#: includes/class-opentrust-admin-ai.php:527 +#: includes/class-ettic-otc-admin-ai.php:527 msgid "Turnstile Site Key" msgstr "" -#: includes/class-opentrust-admin-ai.php:530 +#: includes/class-ettic-otc-admin-ai.php:530 msgid "Public site key from your Cloudflare Turnstile widget." msgstr "" -#: includes/class-opentrust-admin-ai.php:534 +#: includes/class-ettic-otc-admin-ai.php:534 msgid "Turnstile Secret Key" msgstr "" -#: includes/class-opentrust-admin-ai.php:537 +#: includes/class-ettic-otc-admin-ai.php:537 msgid "Enter secret key…" msgstr "" -#: includes/class-opentrust-admin-ai.php:539 +#: includes/class-ettic-otc-admin-ai.php:539 msgid "Key saved" msgstr "" -#: includes/class-opentrust-admin-ai.php:541 +#: includes/class-ettic-otc-admin-ai.php:541 msgid "Secret key from Cloudflare Turnstile. Stored server-side — never exposed to the frontend." msgstr "" -#: includes/class-opentrust-admin-ai.php:546 +#: includes/class-ettic-otc-admin-ai.php:546 msgid "Save AI settings" msgstr "" -#: includes/class-opentrust-admin-ai.php:657 -#: includes/class-opentrust-admin-ai.php:714 -#: includes/class-opentrust-admin-ai.php:751 -#: includes/class-opentrust-admin-ai.php:796 -#: includes/class-opentrust-admin-questions.php:223 -#: includes/class-opentrust-admin-questions.php:264 -#: includes/class-opentrust-admin-questions.php:281 -#: includes/class-opentrust-admin-tools.php:565 +#: includes/class-ettic-otc-admin-ai.php:657 +#: includes/class-ettic-otc-admin-ai.php:714 +#: includes/class-ettic-otc-admin-ai.php:751 +#: includes/class-ettic-otc-admin-ai.php:796 +#: includes/class-ettic-otc-admin-questions.php:223 +#: includes/class-ettic-otc-admin-questions.php:264 +#: includes/class-ettic-otc-admin-questions.php:281 +#: includes/class-ettic-otc-admin-tools.php:565 msgid "You do not have permission to perform this action." msgstr "" -#: includes/class-opentrust-admin-ai.php:666 -#: includes/class-opentrust-admin-ai.php:722 -#: includes/class-opentrust-admin-ai.php:758 +#: includes/class-ettic-otc-admin-ai.php:666 +#: includes/class-ettic-otc-admin-ai.php:722 +#: includes/class-ettic-otc-admin-ai.php:758 msgid "Unknown provider." msgstr "" -#: includes/class-opentrust-admin-ai.php:670 +#: includes/class-ettic-otc-admin-ai.php:670 msgid "API key cannot be empty." msgstr "" -#: includes/class-opentrust-admin-ai.php:677 +#: includes/class-ettic-otc-admin-ai.php:677 msgid "Validation failed." msgstr "" #. translators: 1: provider label, 2: provider error message -#: includes/class-opentrust-admin-ai.php:679 +#: includes/class-ettic-otc-admin-ai.php:679 #, php-format msgid "%1$s rejected the key: %2$s" msgstr "" #. translators: 1: provider label, 2: number of models -#: includes/class-opentrust-admin-ai.php:707 +#: includes/class-ettic-otc-admin-ai.php:707 #, php-format msgid "%1$s key validated. Found %2$d model(s)." msgstr "" -#: includes/class-opentrust-admin-ai.php:745 +#: includes/class-ettic-otc-admin-ai.php:745 msgid "Key removed." msgstr "" -#: includes/class-opentrust-admin-ai.php:764 +#: includes/class-ettic-otc-admin-ai.php:764 msgid "No key on file for this provider." msgstr "" -#: includes/class-opentrust-admin-ai.php:770 +#: includes/class-ettic-otc-admin-ai.php:770 msgid "Refresh failed." msgstr "" #. translators: %s: error message from the provider -#: includes/class-opentrust-admin-ai.php:772 +#: includes/class-ettic-otc-admin-ai.php:772 #, php-format msgid "Refresh failed: %s" msgstr "" #. translators: %d: number of models -#: includes/class-opentrust-admin-ai.php:782 +#: includes/class-ettic-otc-admin-ai.php:782 #, php-format msgid "Model list refreshed. Found %d model(s)." msgstr "" #. translators: %d is the number of policies enqueued for summary generation. -#: includes/class-opentrust-admin-ai.php:812 +#: includes/class-ettic-otc-admin-ai.php:812 #, php-format msgid "Queued %d policy for AI summary generation. Summaries will appear over the next minute." msgid_plural "Queued %d policies for AI summary generation. Summaries will appear over the next few minutes." msgstr[0] "" msgstr[1] "" -#: includes/class-opentrust-admin-ai.php:820 +#: includes/class-ettic-otc-admin-ai.php:820 msgid "All policies already have up-to-date AI summaries." msgstr "" -#: includes/class-opentrust-admin-questions.php:87 +#: includes/class-ettic-otc-admin-questions.php:87 msgid "AI Questions" msgstr "" -#: includes/class-opentrust-admin-questions.php:90 +#: includes/class-ettic-otc-admin-questions.php:90 msgid "Questions visitors have asked your trust center chat. Identifiers are hashed and rows auto-purge after 90 days." msgstr "" -#: includes/class-opentrust-admin-questions.php:96 +#: includes/class-ettic-otc-admin-questions.php:96 msgid "Logging is ON" msgstr "" -#: includes/class-opentrust-admin-questions.php:98 +#: includes/class-ettic-otc-admin-questions.php:98 msgid "Logging is OFF" msgstr "" #. translators: %d: number of questions -#: includes/class-opentrust-admin-questions.php:104 +#: includes/class-ettic-otc-admin-questions.php:104 #, php-format msgid "%d question logged in the last 90 days" msgid_plural "%d questions logged in the last 90 days" msgstr[0] "" msgstr[1] "" -#: includes/class-opentrust-admin-questions.php:108 +#: includes/class-ettic-otc-admin-questions.php:108 msgid "Toggle visitor question logging?" msgstr "" -#: includes/class-opentrust-admin-questions.php:109 +#: includes/class-ettic-otc-admin-questions.php:109 msgid "Disable logging" msgstr "" -#: includes/class-opentrust-admin-questions.php:109 +#: includes/class-ettic-otc-admin-questions.php:109 msgid "Enable logging" msgstr "" -#: includes/class-opentrust-admin-questions.php:117 +#: includes/class-ettic-otc-admin-questions.php:117 msgid "Search" msgstr "" -#: includes/class-opentrust-admin-questions.php:118 +#: includes/class-ettic-otc-admin-questions.php:118 msgid "Search questions…" msgstr "" -#: includes/class-opentrust-admin-questions.php:121 -#: includes/class-opentrust-admin-questions.php:148 +#: includes/class-ettic-otc-admin-questions.php:121 +#: includes/class-ettic-otc-admin-questions.php:148 msgid "Model" msgstr "" -#: includes/class-opentrust-admin-questions.php:123 +#: includes/class-ettic-otc-admin-questions.php:123 msgid "Any" msgstr "" -#: includes/class-opentrust-admin-questions.php:130 +#: includes/class-ettic-otc-admin-questions.php:130 msgid "From" msgstr "" -#: includes/class-opentrust-admin-questions.php:134 +#: includes/class-ettic-otc-admin-questions.php:134 msgid "To" msgstr "" -#: includes/class-opentrust-admin-questions.php:137 +#: includes/class-ettic-otc-admin-questions.php:137 msgid "Filter" msgstr "" -#: includes/class-opentrust-admin-questions.php:138 +#: includes/class-ettic-otc-admin-questions.php:138 msgid "Reset" msgstr "" -#: includes/class-opentrust-admin-questions.php:139 +#: includes/class-ettic-otc-admin-questions.php:139 msgid "Download CSV" msgstr "" -#: includes/class-opentrust-admin-questions.php:146 -#: includes/class-opentrust-version.php:161 +#: includes/class-ettic-otc-admin-questions.php:146 +#: includes/class-ettic-otc-version.php:161 msgid "Date" msgstr "" -#: includes/class-opentrust-admin-questions.php:147 +#: includes/class-ettic-otc-admin-questions.php:147 msgid "Question" msgstr "" -#: includes/class-opentrust-admin-questions.php:149 +#: includes/class-ettic-otc-admin-questions.php:149 msgid "Cites" msgstr "" -#: includes/class-opentrust-admin-questions.php:150 +#: includes/class-ettic-otc-admin-questions.php:150 msgid "Tokens" msgstr "" -#: includes/class-opentrust-admin-questions.php:151 +#: includes/class-ettic-otc-admin-questions.php:151 msgid "Latency" msgstr "" -#: includes/class-opentrust-admin-questions.php:156 +#: includes/class-ettic-otc-admin-questions.php:156 msgid "No questions logged yet." msgstr "" -#: includes/class-opentrust-admin-questions.php:165 +#: includes/class-ettic-otc-admin-questions.php:165 msgid "REFUSED" msgstr "" -#: includes/class-opentrust-admin-questions.php:209 +#: includes/class-ettic-otc-admin-questions.php:209 msgid "Danger zone" msgstr "" -#: includes/class-opentrust-admin-questions.php:210 +#: includes/class-ettic-otc-admin-questions.php:210 msgid "Permanently delete all logged questions? This cannot be undone." msgstr "" -#: includes/class-opentrust-admin-questions.php:211 +#: includes/class-ettic-otc-admin-questions.php:211 msgid "Clear entire question log" msgstr "" -#: includes/class-opentrust-admin-questions.php:272 +#: includes/class-ettic-otc-admin-questions.php:272 msgid "Question log cleared." msgstr "" -#: includes/class-opentrust-admin-questions.php:291 +#: includes/class-ettic-otc-admin-questions.php:291 msgid "Logging enabled." msgstr "" -#: includes/class-opentrust-admin-questions.php:291 +#: includes/class-ettic-otc-admin-questions.php:291 msgid "Logging disabled." msgstr "" -#: includes/class-opentrust-admin-review.php:81 +#: includes/class-ettic-otc-admin-review.php:81 msgid "review on WordPress.org" msgstr "" #. translators: %s: link to the WordPress.org reviews page -#: includes/class-opentrust-admin-review.php:89 +#: includes/class-ettic-otc-admin-review.php:89 #, php-format -msgid "OpenTrust is built and maintained in the open. If it is helping your team, a %s keeps the project moving." +msgid "Ettic_OTC is built and maintained in the open. If it is helping your team, a %s keeps the project moving." msgstr "" -#: includes/class-opentrust-admin-review.php:115 +#: includes/class-ettic-otc-admin-review.php:115 msgid "Your trust center is up and running." msgstr "" -#: includes/class-opentrust-admin-review.php:116 -msgid "OpenTrust is fully open-source with no paid tier — reviews on WordPress.org are how the project gets seen. If it has earned a kind word, we would be grateful." +#: includes/class-ettic-otc-admin-review.php:116 +msgid "Ettic_OTC is fully open-source with no paid tier — reviews on WordPress.org are how the project gets seen. If it has earned a kind word, we would be grateful." msgstr "" -#: includes/class-opentrust-admin-review.php:120 +#: includes/class-ettic-otc-admin-review.php:120 msgid "Leave a review" msgstr "" -#: includes/class-opentrust-admin-review.php:123 +#: includes/class-ettic-otc-admin-review.php:123 msgid "Already did, thanks" msgstr "" -#: includes/class-opentrust-admin-review.php:126 +#: includes/class-ettic-otc-admin-review.php:126 msgid "Not now" msgstr "" -#: includes/class-opentrust-admin-review.php:168 +#: includes/class-ettic-otc-admin-review.php:168 msgid "You do not have permission to dismiss this notice." msgstr "" -#: includes/class-opentrust-admin-settings.php:55 +#: includes/class-ettic-otc-admin-settings.php:55 msgid "General Settings" msgstr "" -#: includes/class-opentrust-admin-settings.php:60 +#: includes/class-ettic-otc-admin-settings.php:60 msgid "Endpoint Slug" msgstr "" -#: includes/class-opentrust-admin-settings.php:61 +#: includes/class-ettic-otc-admin-settings.php:61 msgid "The URL path for your trust center (e.g., \"trust-center\" = yoursite.com/trust-center/)." msgstr "" -#: includes/class-opentrust-admin-settings.php:64 +#: includes/class-ettic-otc-admin-settings.php:64 msgid "Page Title" msgstr "" -#: includes/class-opentrust-admin-settings.php:66 +#: includes/class-ettic-otc-admin-settings.php:66 msgid "Company Name" msgstr "" -#: includes/class-opentrust-admin-settings.php:68 +#: includes/class-ettic-otc-admin-settings.php:68 msgid "Tagline" msgstr "" -#: includes/class-opentrust-admin-settings.php:69 +#: includes/class-ettic-otc-admin-settings.php:69 msgid "A short description displayed below the company name in the hero section." msgstr "" -#: includes/class-opentrust-admin-settings.php:75 +#: includes/class-ettic-otc-admin-settings.php:75 msgid "Branding" msgstr "" -#: includes/class-opentrust-admin-settings.php:80 +#: includes/class-ettic-otc-admin-settings.php:80 msgid "Logo" msgstr "" -#: includes/class-opentrust-admin-settings.php:81 +#: includes/class-ettic-otc-admin-settings.php:81 msgid "AI Avatar" msgstr "" -#: includes/class-opentrust-admin-settings.php:83 +#: includes/class-ettic-otc-admin-settings.php:83 msgid "Accent Color" msgstr "" -#: includes/class-opentrust-admin-settings.php:84 +#: includes/class-ettic-otc-admin-settings.php:84 msgid "Used for buttons, links, and highlights. Choose a color that matches your brand." msgstr "" -#: includes/class-opentrust-admin-settings.php:87 +#: includes/class-ettic-otc-admin-settings.php:87 msgid "Credit Link" msgstr "" -#: includes/class-opentrust-admin-settings.php:92 +#: includes/class-ettic-otc-admin-settings.php:92 msgid "Visible Sections" msgstr "" -#: includes/class-opentrust-admin-settings.php:93 +#: includes/class-ettic-otc-admin-settings.php:93 msgid "Choose which sections to display on the trust center." msgstr "" -#: includes/class-opentrust-admin-settings.php:97 +#: includes/class-ettic-otc-admin-settings.php:97 msgid "Sections" msgstr "" -#: includes/class-opentrust-admin-settings.php:103 +#: includes/class-ettic-otc-admin-settings.php:103 #: templates/partials/contact.php:111 msgid "Get in touch" msgstr "" -#: includes/class-opentrust-admin-settings.php:104 +#: includes/class-ettic-otc-admin-settings.php:104 msgid "Publish a dark-accent \"Get in touch\" block on the trust center. Every field is optional — the block only appears if at least one is filled in." msgstr "" -#: includes/class-opentrust-admin-settings.php:108 +#: includes/class-ettic-otc-admin-settings.php:108 msgid "Company Description" msgstr "" -#: includes/class-opentrust-admin-settings.php:109 +#: includes/class-ettic-otc-admin-settings.php:109 msgid "Two or three sentences describing what the company does. Rendered under the \"Get in touch\" section title." msgstr "" -#: includes/class-opentrust-admin-settings.php:112 +#: includes/class-ettic-otc-admin-settings.php:112 msgid "DPO Name" msgstr "" -#: includes/class-opentrust-admin-settings.php:113 +#: includes/class-ettic-otc-admin-settings.php:113 msgid "Data Protection Officer name. Required under GDPR for many organisations." msgstr "" -#: includes/class-opentrust-admin-settings.php:116 +#: includes/class-ettic-otc-admin-settings.php:116 msgid "DPO Email" msgstr "" -#: includes/class-opentrust-admin-settings.php:117 +#: includes/class-ettic-otc-admin-settings.php:117 msgid "Dedicated DPO mailbox. Rendered as a mailto link." msgstr "" -#: includes/class-opentrust-admin-settings.php:120 +#: includes/class-ettic-otc-admin-settings.php:120 msgid "Security Contact Email" msgstr "" -#: includes/class-opentrust-admin-settings.php:121 +#: includes/class-ettic-otc-admin-settings.php:121 msgid "For vulnerability reports and security questions. Often separate from the DPO." msgstr "" -#: includes/class-opentrust-admin-settings.php:124 +#: includes/class-ettic-otc-admin-settings.php:124 msgid "Contact Form URL" msgstr "" -#: includes/class-opentrust-admin-settings.php:125 +#: includes/class-ettic-otc-admin-settings.php:125 msgid "Optional link to a gated contact form." msgstr "" -#: includes/class-opentrust-admin-settings.php:128 +#: includes/class-ettic-otc-admin-settings.php:128 #: templates/partials/contact.php:84 msgid "Mailing Address" msgstr "" -#: includes/class-opentrust-admin-settings.php:129 +#: includes/class-ettic-otc-admin-settings.php:129 msgid "Postal address for formal GDPR / legal notices." msgstr "" -#: includes/class-opentrust-admin-settings.php:132 +#: includes/class-ettic-otc-admin-settings.php:132 msgid "PGP Public Key URL" msgstr "" -#: includes/class-opentrust-admin-settings.php:133 +#: includes/class-ettic-otc-admin-settings.php:133 msgid "Optional link to your security team's PGP public key." msgstr "" -#: includes/class-opentrust-admin-settings.php:136 +#: includes/class-ettic-otc-admin-settings.php:136 msgid "Company Registration Number" msgstr "" -#: includes/class-opentrust-admin-settings.php:137 +#: includes/class-ettic-otc-admin-settings.php:137 msgid "KvK (NL), Companies House (UK), Handelsregister (DE), EIN (US), or equivalent business registration." msgstr "" -#: includes/class-opentrust-admin-settings.php:140 +#: includes/class-ettic-otc-admin-settings.php:140 #: templates/partials/contact.php:100 msgid "VAT / Tax ID" msgstr "" -#: includes/class-opentrust-admin-settings.php:141 +#: includes/class-ettic-otc-admin-settings.php:141 msgid "VAT number, sales-tax ID, or equivalent international tax identifier." msgstr "" -#: includes/class-opentrust-admin-settings.php:222 +#: includes/class-ettic-otc-admin-settings.php:222 msgid "Low contrast on white backgrounds" msgstr "" -#: includes/class-opentrust-admin-settings.php:223 +#: includes/class-ettic-otc-admin-settings.php:223 msgid "Using your exact color on white backgrounds" msgstr "" -#: includes/class-opentrust-admin-settings.php:226 -msgid "Your chosen color is too light for buttons, links, and borders on white sections. On those surfaces OpenTrust will use a darker, on-brand variant:" +#: includes/class-ettic-otc-admin-settings.php:226 +msgid "Your chosen color is too light for buttons, links, and borders on white sections. On those surfaces Ettic_OTC will use a darker, on-brand variant:" msgstr "" -#: includes/class-opentrust-admin-settings.php:229 +#: includes/class-ettic-otc-admin-settings.php:229 msgid "You've chosen to keep your exact color on white backgrounds. Buttons, links, and borders in those sections may be hard to read." msgstr "" -#: includes/class-opentrust-admin-settings.php:241 +#: includes/class-ettic-otc-admin-settings.php:241 msgid "The hero and navigation still use your exact color." msgstr "" -#: includes/class-opentrust-admin-settings.php:252 +#: includes/class-ettic-otc-admin-settings.php:252 msgid "Use my exact color anyway — skip the contrast adjustment." msgstr "" -#: includes/class-opentrust-admin-settings.php:265 -#: includes/class-opentrust-cpt.php:479 +#: includes/class-ettic-otc-admin-settings.php:265 +#: includes/class-ettic-otc-cpt.php:475 msgid "Select Logo" msgstr "" -#: includes/class-opentrust-admin-settings.php:266 +#: includes/class-ettic-otc-admin-settings.php:266 msgid "Used in the hero and sticky nav. A white version is recommended — it sits on a dark background." msgstr "" -#: includes/class-opentrust-admin-settings.php:273 +#: includes/class-ettic-otc-admin-settings.php:273 msgid "Select Avatar" msgstr "" -#: includes/class-opentrust-admin-settings.php:274 +#: includes/class-ettic-otc-admin-settings.php:274 msgid "Square image used as the avatar on AI chat responses. Use a colored background with a light or dark favicon or logo on top." msgstr "" -#: includes/class-opentrust-admin-settings.php:289 -#: includes/class-opentrust-cpt.php:480 -#: includes/class-opentrust-cpt.php:492 -#: includes/class-opentrust-cpt.php:623 -#: includes/class-opentrust-cpt.php:639 -#: includes/class-opentrust-cpt.php:725 -#: includes/class-opentrust-cpt.php:763 +#: includes/class-ettic-otc-admin-settings.php:289 +#: includes/class-ettic-otc-cpt.php:476 +#: includes/class-ettic-otc-cpt.php:488 +#: includes/class-ettic-otc-cpt.php:619 +#: includes/class-ettic-otc-cpt.php:635 +#: includes/class-ettic-otc-cpt.php:721 +#: includes/class-ettic-otc-cpt.php:759 msgid "Remove" msgstr "" -#: includes/class-opentrust-admin-settings.php:301 -msgid "Show a \"Powered by OpenTrust\" credit in the trust center footer." +#: includes/class-ettic-otc-admin-settings.php:301 +msgid "Show a \"Powered by Open Trust Center\" credit in the trust center footer." msgstr "" -#: includes/class-opentrust-admin-settings.php:305 +#: includes/class-ettic-otc-admin-settings.php:305 msgid "Off by default. Public credits are opt-in." msgstr "" -#: includes/class-opentrust-admin-settings.php:314 +#: includes/class-ettic-otc-admin-settings.php:314 #: templates/partials/certifications.php:22 msgid "Certifications & Compliance" msgstr "" -#: includes/class-opentrust-admin-settings.php:315 -#: includes/class-opentrust-admin-tools.php:592 -#: includes/class-opentrust-cpt.php:240 -#: includes/class-opentrust-cpt.php:250 +#: includes/class-ettic-otc-admin-settings.php:315 +#: includes/class-ettic-otc-admin-tools.php:592 +#: includes/class-ettic-otc-cpt.php:236 +#: includes/class-ettic-otc-cpt.php:246 #: templates/chat.php:45 #: templates/partials/hero.php:55 #: templates/trust-center.php:107 msgid "Policies" msgstr "" -#: includes/class-opentrust-admin-settings.php:316 -#: includes/class-opentrust-admin-tools.php:594 -#: includes/class-opentrust-cpt.php:307 -#: includes/class-opentrust-cpt.php:316 +#: includes/class-ettic-otc-admin-settings.php:316 +#: includes/class-ettic-otc-admin-tools.php:594 +#: includes/class-ettic-otc-cpt.php:303 +#: includes/class-ettic-otc-cpt.php:312 #: templates/chat.php:47 #: templates/partials/hero.php:61 #: templates/partials/subprocessors.php:20 @@ -780,1008 +778,1013 @@ msgstr "" msgid "Subprocessors" msgstr "" -#: includes/class-opentrust-admin-settings.php:317 -#: includes/class-opentrust-admin-tools.php:595 -#: includes/class-opentrust-cpt.php:340 -#: includes/class-opentrust-cpt.php:349 +#: includes/class-ettic-otc-admin-settings.php:317 +#: includes/class-ettic-otc-admin-tools.php:595 +#: includes/class-ettic-otc-cpt.php:336 +#: includes/class-ettic-otc-cpt.php:345 #: templates/chat.php:48 #: templates/partials/data-practices.php:34 #: templates/trust-center.php:110 msgid "Data Practices" msgstr "" -#: includes/class-opentrust-admin-settings.php:318 -#: includes/class-opentrust-admin-tools.php:596 -#: includes/class-opentrust-cpt.php:373 -#: includes/class-opentrust-cpt.php:383 +#: includes/class-ettic-otc-admin-settings.php:318 +#: includes/class-ettic-otc-admin-tools.php:596 +#: includes/class-ettic-otc-cpt.php:369 +#: includes/class-ettic-otc-cpt.php:379 msgid "FAQs" msgstr "" -#: includes/class-opentrust-admin-settings.php:319 +#: includes/class-ettic-otc-admin-settings.php:319 msgid "Contact & DPO" msgstr "" -#: includes/class-opentrust-admin-settings.php:586 +#: includes/class-ettic-otc-admin-settings.php:586 msgid "View Trust Center" msgstr "" -#: includes/class-opentrust-admin-settings.php:593 -#: includes/class-opentrust-render.php:515 +#: includes/class-ettic-otc-admin-settings.php:593 +#: includes/class-ettic-otc-render.php:515 msgid "General" msgstr "" -#: includes/class-opentrust-admin-settings.php:597 +#: includes/class-ettic-otc-admin-settings.php:597 #: templates/chat.php:60 #: templates/trust-center.php:111 msgid "Contact" msgstr "" -#: includes/class-opentrust-admin-settings.php:601 +#: includes/class-ettic-otc-admin-settings.php:601 msgid "AI Chat" msgstr "" -#: includes/class-opentrust-admin-settings.php:604 +#: includes/class-ettic-otc-admin-settings.php:604 msgid "Live" msgstr "" -#: includes/class-opentrust-admin-settings.php:610 +#: includes/class-ettic-otc-admin-settings.php:610 msgid "Import & Export" msgstr "" -#: includes/class-opentrust-admin-tools.php:155 +#: includes/class-ettic-otc-admin-tools.php:155 msgid "Move trust center content and settings between sites, or seed a fresh install from another. API keys and the Turnstile secret are never included — re-enter them on the destination." msgstr "" -#: includes/class-opentrust-admin-tools.php:163 +#: includes/class-ettic-otc-admin-tools.php:163 msgid "Export" msgstr "" -#: includes/class-opentrust-admin-tools.php:167 +#: includes/class-ettic-otc-admin-tools.php:167 msgid "Import" msgstr "" -#: includes/class-opentrust-admin-tools.php:183 +#: includes/class-ettic-otc-admin-tools.php:183 msgid "What to export" msgstr "" -#: includes/class-opentrust-admin-tools.php:186 +#: includes/class-ettic-otc-admin-tools.php:186 msgid "Content (CPTs + bundled media)" msgstr "" -#: includes/class-opentrust-admin-tools.php:190 +#: includes/class-ettic-otc-admin-tools.php:190 msgid "Settings only" msgstr "" -#: includes/class-opentrust-admin-tools.php:195 +#: includes/class-ettic-otc-admin-tools.php:195 msgid "Content selection" msgstr "" -#: includes/class-opentrust-admin-tools.php:225 +#: includes/class-ettic-otc-admin-tools.php:225 msgid "Bundle attached PDFs and images" msgstr "" -#: includes/class-opentrust-admin-tools.php:229 +#: includes/class-ettic-otc-admin-tools.php:229 msgid "Download export" msgstr "" -#: includes/class-opentrust-admin-tools.php:243 +#: includes/class-ettic-otc-admin-tools.php:243 msgid "Only upload your own exports." msgstr "" -#: includes/class-opentrust-admin-tools.php:244 +#: includes/class-ettic-otc-admin-tools.php:244 msgid "Export files contain your trust-center content and may include sensitive material. Never import a file you received from someone else." msgstr "" -#: includes/class-opentrust-admin-tools.php:248 +#: includes/class-ettic-otc-admin-tools.php:248 msgid "Upload export file" msgstr "" #. translators: %d: max upload size in MB -#: includes/class-opentrust-admin-tools.php:253 +#: includes/class-ettic-otc-admin-tools.php:253 #, php-format msgid "Max %d MB" msgstr "" -#: includes/class-opentrust-admin-tools.php:259 +#: includes/class-ettic-otc-admin-tools.php:259 msgid "On conflict" msgstr "" -#: includes/class-opentrust-admin-tools.php:262 +#: includes/class-ettic-otc-admin-tools.php:262 msgid "Skip — keep existing records untouched" msgstr "" -#: includes/class-opentrust-admin-tools.php:266 +#: includes/class-ettic-otc-admin-tools.php:266 msgid "Overwrite — replace existing records" msgstr "" -#: includes/class-opentrust-admin-tools.php:270 +#: includes/class-ettic-otc-admin-tools.php:270 msgid "Create new — duplicate with a -import suffix" msgstr "" -#: includes/class-opentrust-admin-tools.php:275 +#: includes/class-ettic-otc-admin-tools.php:275 msgid "Preview import" msgstr "" -#: includes/class-opentrust-admin-tools.php:292 +#: includes/class-ettic-otc-admin-tools.php:292 msgid "Import preview" msgstr "" -#: includes/class-opentrust-admin-tools.php:296 +#: includes/class-ettic-otc-admin-tools.php:296 msgid "Import blocked:" msgstr "" -#: includes/class-opentrust-admin-tools.php:317 +#: includes/class-ettic-otc-admin-tools.php:317 msgid "Settings export — current values will be merged with imported values. Excluded keys (encrypted secrets, salt, server-controlled flags) are kept as-is." msgstr "" #. translators: %1$d: create count, %2$d: update count, %3$d: skip count -#: includes/class-opentrust-admin-tools.php:324 +#: includes/class-ettic-otc-admin-tools.php:324 #, php-format msgid "Will create %1$d, update %2$d, skip %3$d." msgstr "" -#: includes/class-opentrust-admin-tools.php:338 +#: includes/class-ettic-otc-admin-tools.php:338 msgid "Title" msgstr "" -#: includes/class-opentrust-admin-tools.php:339 +#: includes/class-ettic-otc-admin-tools.php:339 msgid "Action" msgstr "" -#: includes/class-opentrust-admin-tools.php:340 +#: includes/class-ettic-otc-admin-tools.php:340 msgid "UUID" msgstr "" -#: includes/class-opentrust-admin-tools.php:361 +#: includes/class-ettic-otc-admin-tools.php:361 msgid "Confirm and import" msgstr "" -#: includes/class-opentrust-admin-tools.php:363 +#: includes/class-ettic-otc-admin-tools.php:363 msgid "Cancel" msgstr "" -#: includes/class-opentrust-admin-tools.php:385 +#: includes/class-ettic-otc-admin-tools.php:385 msgid "Pick at least one record to export." msgstr "" -#: includes/class-opentrust-admin-tools.php:415 +#: includes/class-ettic-otc-admin-tools.php:415 msgid "No file uploaded." msgstr "" -#: includes/class-opentrust-admin-tools.php:421 +#: includes/class-ettic-otc-admin-tools.php:421 msgid "Upload exceeds size limit." msgstr "" -#: includes/class-opentrust-admin-tools.php:514 +#: includes/class-ettic-otc-admin-tools.php:514 msgid "Import cancelled." msgstr "" -#: includes/class-opentrust-admin-tools.php:519 +#: includes/class-ettic-otc-admin-tools.php:519 msgid "Import has unresolved errors." msgstr "" #. translators: %1$d: created, %2$d: updated, %3$d: skipped -#: includes/class-opentrust-admin-tools.php:539 +#: includes/class-ettic-otc-admin-tools.php:539 #, php-format msgid "Imported: %1$d created, %2$d updated, %3$d skipped." msgstr "" -#: includes/class-opentrust-admin-tools.php:547 +#: includes/class-ettic-otc-admin-tools.php:547 msgid "Errors:" msgstr "" -#: includes/class-opentrust-admin-tools.php:593 -#: includes/class-opentrust-cpt.php:274 -#: includes/class-opentrust-cpt.php:283 +#: includes/class-ettic-otc-admin-tools.php:593 +#: includes/class-ettic-otc-cpt.php:270 +#: includes/class-ettic-otc-cpt.php:279 #: templates/chat.php:46 #: templates/partials/hero.php:49 #: templates/trust-center.php:108 msgid "Certifications" msgstr "" -#: includes/class-opentrust-admin.php:67 -#: includes/class-opentrust-admin.php:68 +#: includes/class-ettic-otc-admin.php:56 +#: includes/class-ettic-otc-admin.php:57 +msgid "Open Trust Center" +msgstr "" + +#: includes/class-ettic-otc-admin.php:67 +#: includes/class-ettic-otc-admin.php:68 msgid "Settings" msgstr "" -#: includes/class-opentrust-admin.php:79 -#: includes/class-opentrust-admin.php:80 +#: includes/class-ettic-otc-admin.php:79 +#: includes/class-ettic-otc-admin.php:80 msgid "Questions" msgstr "" -#: includes/class-opentrust-admin.php:158 +#: includes/class-ettic-otc-admin.php:158 msgid "Select Badge Image" msgstr "" -#: includes/class-opentrust-admin.php:159 +#: includes/class-ettic-otc-admin.php:159 msgid "Use as Badge" msgstr "" -#: includes/class-opentrust-admin.php:160 +#: includes/class-ettic-otc-admin.php:160 msgid "Select Proof Artifact" msgstr "" -#: includes/class-opentrust-admin.php:161 +#: includes/class-ettic-otc-admin.php:161 msgid "Use This File" msgstr "" -#: includes/class-opentrust-admin.php:162 -#: includes/class-opentrust-cpt.php:491 +#: includes/class-ettic-otc-admin.php:162 +#: includes/class-ettic-otc-cpt.php:487 msgid "Upload File" msgstr "" -#: includes/class-opentrust-admin.php:163 -#: includes/class-opentrust-cpt.php:491 +#: includes/class-ettic-otc-admin.php:163 +#: includes/class-ettic-otc-cpt.php:487 msgid "Replace File" msgstr "" -#: includes/class-opentrust-admin.php:178 +#: includes/class-ettic-otc-admin.php:178 msgid "No match in catalog, just keep typing to add manually." msgstr "" -#: includes/class-opentrust-admin.php:179 +#: includes/class-ettic-otc-admin.php:179 msgid "Auto-filled from catalog, you may want to verify this." msgstr "" -#: includes/class-opentrust-admin.php:180 +#: includes/class-ettic-otc-admin.php:180 msgid "Auto-filled template, please verify this matches how you use this service." msgstr "" -#: includes/class-opentrust-admin.php:181 +#: includes/class-ettic-otc-admin.php:181 msgid "click to autofill" msgstr "" -#: includes/class-opentrust-admin.php:182 +#: includes/class-ettic-otc-admin.php:182 msgid "Catalog suggestions" msgstr "" -#: includes/class-opentrust-admin.php:228 -msgid "OpenTrust requires pretty permalinks." +#: includes/class-ettic-otc-admin.php:228 +msgid "Ettic_OTC requires pretty permalinks." msgstr "" #. translators: %s: link to Settings → Permalinks -#: includes/class-opentrust-admin.php:232 +#: includes/class-ettic-otc-admin.php:232 #, php-format msgid "Your site is using \"Plain\" permalinks. Please go to %s and choose any other option (Post name is the WordPress default)." msgstr "" -#: includes/class-opentrust-admin.php:233 +#: includes/class-ettic-otc-admin.php:233 msgid "Settings → Permalinks" msgstr "" -#: includes/class-opentrust-admin.php:238 -msgid "Without pretty permalinks, every link OpenTrust generates returns 404 — including the trust center page itself. Visitors will not be able to reach your policies, certifications, or chat." +#: includes/class-ettic-otc-admin.php:238 +msgid "Without pretty permalinks, every link Ettic_OTC generates returns 404 — including the trust center page itself. Visitors will not be able to reach your policies, certifications, or chat." msgstr "" -#: includes/class-opentrust-admin.php:242 +#: includes/class-ettic-otc-admin.php:242 msgid "Read-only fallback if you cannot change permalinks" msgstr "" -#: includes/class-opentrust-admin.php:246 +#: includes/class-ettic-otc-admin.php:246 msgid "You can preview the trust center via raw query-string URLs:" msgstr "" -#: includes/class-opentrust-admin.php:254 +#: includes/class-ettic-otc-admin.php:254 msgid "This is for testing only." msgstr "" -#: includes/class-opentrust-admin.php:255 +#: includes/class-ettic-otc-admin.php:255 msgid "Switching to pretty permalinks is the only supported configuration." msgstr "" -#: includes/class-opentrust-chat.php:112 +#: includes/class-ettic-otc-chat.php:112 msgid "Invalid nonce — refresh the page and try again." msgstr "" -#: includes/class-opentrust-chat.php:140 +#: includes/class-ettic-otc-chat.php:140 msgid "Please complete the anti-abuse challenge and try again." msgstr "" -#: includes/class-opentrust-chat.php:152 +#: includes/class-ettic-otc-chat.php:152 msgid "You are sending messages too fast. Please wait a moment and try again." msgstr "" -#: includes/class-opentrust-chat.php:163 +#: includes/class-ettic-otc-chat.php:163 msgid "You have reached the per-session message limit. Please wait a bit and try again." msgstr "" -#: includes/class-opentrust-chat.php:183 +#: includes/class-ettic-otc-chat.php:183 msgid "AI chat is not configured on this site." msgstr "" -#: includes/class-opentrust-chat.php:192 +#: includes/class-ettic-otc-chat.php:192 msgid "Configured provider is unknown." msgstr "" -#: includes/class-opentrust-chat.php:201 +#: includes/class-ettic-otc-chat.php:201 msgid "No API key stored for the configured provider." msgstr "" -#: includes/class-opentrust-chat.php:214 +#: includes/class-ettic-otc-chat.php:214 msgid "Your message is empty." msgstr "" -#: includes/class-opentrust-chat.php:232 +#: includes/class-ettic-otc-chat.php:232 msgid "The daily chat budget for this site has been reached. Please try again later." msgstr "" -#: includes/class-opentrust-chat.php:394 +#: includes/class-ettic-otc-chat.php:394 msgid "Chat provider failed unexpectedly." msgstr "" #. translators: %s is the tool name (get_document or search_documents). -#: includes/class-opentrust-chat.php:722 +#: includes/class-ettic-otc-chat.php:722 #, php-format msgid "You already called %s with the same arguments earlier in this conversation. Pick a different document id from the index, or rephrase the search query with different keywords." msgstr "" -#: includes/class-opentrust-chat.php:732 +#: includes/class-ettic-otc-chat.php:732 msgid "Document id is required." msgstr "" #. translators: %s is the requested document id. -#: includes/class-opentrust-chat.php:741 +#: includes/class-ettic-otc-chat.php:741 #, php-format msgid "No document with id \"%s\". Pick one of the ids listed in the corpus index above." msgstr "" -#: includes/class-opentrust-chat.php:749 +#: includes/class-ettic-otc-chat.php:749 msgid "Search query is empty." msgstr "" -#: includes/class-opentrust-chat.php:752 +#: includes/class-ettic-otc-chat.php:752 msgid "Search index unavailable." msgstr "" #. translators: %s is the search query. -#: includes/class-opentrust-chat.php:758 +#: includes/class-ettic-otc-chat.php:758 #, php-format msgid "No documents matched \"%s\". Try broader keywords or pick a document id from the corpus index above." msgstr "" -#: includes/class-opentrust-chat.php:770 +#: includes/class-ettic-otc-chat.php:770 msgid "Search ranking returned no usable results." msgstr "" #. translators: %s is the unknown tool name. -#: includes/class-opentrust-chat.php:775 +#: includes/class-ettic-otc-chat.php:775 #, php-format msgid "Unknown tool: %s" msgstr "" -#: includes/class-opentrust-cpt.php:221 +#: includes/class-ettic-otc-cpt.php:217 msgid "Pick from the catalog or type your own subprocessor name" msgstr "" -#: includes/class-opentrust-cpt.php:224 +#: includes/class-ettic-otc-cpt.php:220 msgid "Pick from the catalog or type your own, e.g. Analytics or Transactional Email" msgstr "" -#: includes/class-opentrust-cpt.php:227 +#: includes/class-ettic-otc-cpt.php:223 msgid "Pick from the catalog or type your own, e.g. SOC 2 Type II or ISO 27001" msgstr "" -#: includes/class-opentrust-cpt.php:241 +#: includes/class-ettic-otc-cpt.php:237 #: templates/partials/policies.php:54 msgid "Policy" msgstr "" -#: includes/class-opentrust-cpt.php:242 +#: includes/class-ettic-otc-cpt.php:238 msgid "Add Policy" msgstr "" -#: includes/class-opentrust-cpt.php:243 +#: includes/class-ettic-otc-cpt.php:239 msgid "Add New Policy" msgstr "" -#: includes/class-opentrust-cpt.php:244 +#: includes/class-ettic-otc-cpt.php:240 msgid "Edit Policy" msgstr "" -#: includes/class-opentrust-cpt.php:245 +#: includes/class-ettic-otc-cpt.php:241 msgid "New Policy" msgstr "" -#: includes/class-opentrust-cpt.php:246 +#: includes/class-ettic-otc-cpt.php:242 msgid "View Policy" msgstr "" -#: includes/class-opentrust-cpt.php:247 +#: includes/class-ettic-otc-cpt.php:243 msgid "Search Policies" msgstr "" -#: includes/class-opentrust-cpt.php:248 +#: includes/class-ettic-otc-cpt.php:244 msgid "No policies found." msgstr "" -#: includes/class-opentrust-cpt.php:249 +#: includes/class-ettic-otc-cpt.php:245 msgid "No policies in trash." msgstr "" -#: includes/class-opentrust-cpt.php:275 +#: includes/class-ettic-otc-cpt.php:271 msgid "Certification" msgstr "" -#: includes/class-opentrust-cpt.php:276 +#: includes/class-ettic-otc-cpt.php:272 msgid "Add Certification" msgstr "" -#: includes/class-opentrust-cpt.php:277 +#: includes/class-ettic-otc-cpt.php:273 msgid "Add New Certification" msgstr "" -#: includes/class-opentrust-cpt.php:278 +#: includes/class-ettic-otc-cpt.php:274 msgid "Edit Certification" msgstr "" -#: includes/class-opentrust-cpt.php:279 +#: includes/class-ettic-otc-cpt.php:275 msgid "New Certification" msgstr "" -#: includes/class-opentrust-cpt.php:280 +#: includes/class-ettic-otc-cpt.php:276 msgid "Search Certifications" msgstr "" -#: includes/class-opentrust-cpt.php:281 +#: includes/class-ettic-otc-cpt.php:277 msgid "No certifications found." msgstr "" -#: includes/class-opentrust-cpt.php:282 +#: includes/class-ettic-otc-cpt.php:278 msgid "No certifications in trash." msgstr "" -#: includes/class-opentrust-cpt.php:308 +#: includes/class-ettic-otc-cpt.php:304 msgid "Subprocessor" msgstr "" -#: includes/class-opentrust-cpt.php:309 +#: includes/class-ettic-otc-cpt.php:305 msgid "Add Subprocessor" msgstr "" -#: includes/class-opentrust-cpt.php:310 +#: includes/class-ettic-otc-cpt.php:306 msgid "Add New Subprocessor" msgstr "" -#: includes/class-opentrust-cpt.php:311 +#: includes/class-ettic-otc-cpt.php:307 msgid "Edit Subprocessor" msgstr "" -#: includes/class-opentrust-cpt.php:312 +#: includes/class-ettic-otc-cpt.php:308 msgid "New Subprocessor" msgstr "" -#: includes/class-opentrust-cpt.php:313 +#: includes/class-ettic-otc-cpt.php:309 msgid "Search Subprocessors" msgstr "" -#: includes/class-opentrust-cpt.php:314 +#: includes/class-ettic-otc-cpt.php:310 msgid "No subprocessors found." msgstr "" -#: includes/class-opentrust-cpt.php:315 +#: includes/class-ettic-otc-cpt.php:311 msgid "No subprocessors in trash." msgstr "" -#: includes/class-opentrust-cpt.php:341 +#: includes/class-ettic-otc-cpt.php:337 msgid "Data Practice" msgstr "" -#: includes/class-opentrust-cpt.php:342 +#: includes/class-ettic-otc-cpt.php:338 msgid "Add Data Practice" msgstr "" -#: includes/class-opentrust-cpt.php:343 +#: includes/class-ettic-otc-cpt.php:339 msgid "Add New Data Practice" msgstr "" -#: includes/class-opentrust-cpt.php:344 +#: includes/class-ettic-otc-cpt.php:340 msgid "Edit Data Practice" msgstr "" -#: includes/class-opentrust-cpt.php:345 +#: includes/class-ettic-otc-cpt.php:341 msgid "New Data Practice" msgstr "" -#: includes/class-opentrust-cpt.php:346 +#: includes/class-ettic-otc-cpt.php:342 msgid "Search Data Practices" msgstr "" -#: includes/class-opentrust-cpt.php:347 +#: includes/class-ettic-otc-cpt.php:343 msgid "No data practices found." msgstr "" -#: includes/class-opentrust-cpt.php:348 +#: includes/class-ettic-otc-cpt.php:344 msgid "No data practices in trash." msgstr "" -#: includes/class-opentrust-cpt.php:374 +#: includes/class-ettic-otc-cpt.php:370 #: templates/chat.php:61 #: templates/trust-center.php:112 msgid "FAQ" msgstr "" -#: includes/class-opentrust-cpt.php:375 +#: includes/class-ettic-otc-cpt.php:371 msgid "Add FAQ" msgstr "" -#: includes/class-opentrust-cpt.php:376 +#: includes/class-ettic-otc-cpt.php:372 msgid "Add New FAQ" msgstr "" -#: includes/class-opentrust-cpt.php:377 +#: includes/class-ettic-otc-cpt.php:373 msgid "Edit FAQ" msgstr "" -#: includes/class-opentrust-cpt.php:378 +#: includes/class-ettic-otc-cpt.php:374 msgid "New FAQ" msgstr "" -#: includes/class-opentrust-cpt.php:379 +#: includes/class-ettic-otc-cpt.php:375 msgid "View FAQ" msgstr "" -#: includes/class-opentrust-cpt.php:380 +#: includes/class-ettic-otc-cpt.php:376 msgid "Search FAQs" msgstr "" -#: includes/class-opentrust-cpt.php:381 +#: includes/class-ettic-otc-cpt.php:377 msgid "No FAQs found." msgstr "" -#: includes/class-opentrust-cpt.php:382 +#: includes/class-ettic-otc-cpt.php:378 msgid "No FAQs in trash." msgstr "" -#: includes/class-opentrust-cpt.php:405 +#: includes/class-ettic-otc-cpt.php:401 msgid "Certification Details" msgstr "" -#: includes/class-opentrust-cpt.php:406 +#: includes/class-ettic-otc-cpt.php:402 msgid "Policy Details" msgstr "" -#: includes/class-opentrust-cpt.php:407 +#: includes/class-ettic-otc-cpt.php:403 msgid "Subprocessor Details" msgstr "" -#: includes/class-opentrust-cpt.php:408 +#: includes/class-ettic-otc-cpt.php:404 msgid "Data Practice Details" msgstr "" -#: includes/class-opentrust-cpt.php:409 +#: includes/class-ettic-otc-cpt.php:405 msgid "FAQ Details" msgstr "" -#: includes/class-opentrust-cpt.php:430 +#: includes/class-ettic-otc-cpt.php:426 msgid "Audited certification (issued by a third party)" msgstr "" -#: includes/class-opentrust-cpt.php:431 +#: includes/class-ettic-otc-cpt.php:427 msgid "Self-attested alignment (no external audit)" msgstr "" -#: includes/class-opentrust-cpt.php:435 +#: includes/class-ettic-otc-cpt.php:431 msgid "Active / currently met" msgstr "" -#: includes/class-opentrust-cpt.php:436 +#: includes/class-ettic-otc-cpt.php:432 msgid "In progress" msgstr "" -#: includes/class-opentrust-cpt.php:437 +#: includes/class-ettic-otc-cpt.php:433 msgid "Expired / lapsed" msgstr "" -#: includes/class-opentrust-cpt.php:441 +#: includes/class-ettic-otc-cpt.php:437 msgid "Certification Type" msgstr "" -#: includes/class-opentrust-cpt.php:447 +#: includes/class-ettic-otc-cpt.php:443 msgid "Audited means a third-party issued a formal certificate with dates (SOC 2, ISO 27001, PCI DSS). Self-attested means you adhere to the framework without an external audit — the honest framing for GDPR, CCPA, and most HIPAA posture claims." msgstr "" -#: includes/class-opentrust-cpt.php:451 -#: includes/class-opentrust-cpt.php:1026 +#: includes/class-ettic-otc-cpt.php:447 +#: includes/class-ettic-otc-cpt.php:1022 msgid "Status" msgstr "" -#: includes/class-opentrust-cpt.php:457 +#: includes/class-ettic-otc-cpt.php:453 msgid "\"Active\" for audited means you hold a current certificate. \"Active\" for self-attested means you currently meet the framework. Use \"In progress\" while working toward either." msgstr "" -#: includes/class-opentrust-cpt.php:461 -#: includes/class-opentrust-cpt.php:1025 +#: includes/class-ettic-otc-cpt.php:457 +#: includes/class-ettic-otc-cpt.php:1021 msgid "Issuing Body" msgstr "" -#: includes/class-opentrust-cpt.php:462 +#: includes/class-ettic-otc-cpt.php:458 msgid "e.g., AICPA, BSI Group, Schellman" msgstr "" -#: includes/class-opentrust-cpt.php:466 +#: includes/class-ettic-otc-cpt.php:462 msgid "Issue Date" msgstr "" -#: includes/class-opentrust-cpt.php:471 -#: includes/class-opentrust-cpt.php:1027 +#: includes/class-ettic-otc-cpt.php:467 +#: includes/class-ettic-otc-cpt.php:1023 msgid "Expiry Date" msgstr "" -#: includes/class-opentrust-cpt.php:476 +#: includes/class-ettic-otc-cpt.php:472 msgid "Framework Logo" msgstr "" -#: includes/class-opentrust-cpt.php:481 +#: includes/class-ettic-otc-cpt.php:477 msgid "Use the official framework mark where licensing allows (SOC 2, ISO, GDPR shield). Square images work best at 44×44." msgstr "" -#: includes/class-opentrust-cpt.php:485 +#: includes/class-ettic-otc-cpt.php:481 msgid "Proof Artifact" msgstr "" -#: includes/class-opentrust-cpt.php:488 -#: includes/class-opentrust-cpt.php:635 +#: includes/class-ettic-otc-cpt.php:484 +#: includes/class-ettic-otc-cpt.php:631 msgid "View file" msgstr "" -#: includes/class-opentrust-cpt.php:493 +#: includes/class-ettic-otc-cpt.php:489 msgid "Optional PDF the trust center can link to — e.g. the audit report, certificate, or policy mapping document. Shown as a download button on the card." msgstr "" -#: includes/class-opentrust-cpt.php:497 +#: includes/class-ettic-otc-cpt.php:493 msgid "Scope & Notes" msgstr "" -#: includes/class-opentrust-cpt.php:498 +#: includes/class-ettic-otc-cpt.php:494 msgid "e.g., We process EU personal data under GDPR. Our DPA covers customer data, and we support DSARs within 30 days." msgstr "" -#: includes/class-opentrust-cpt.php:499 +#: includes/class-ettic-otc-cpt.php:495 msgid "Required for self-attested frameworks so the card has meaningful content. One or two sentences on scope, how you meet the framework, or what prospects should know." msgstr "" #. translators: %s: policy version number -#: includes/class-opentrust-cpt.php:554 +#: includes/class-ettic-otc-cpt.php:550 #, php-format msgid "Version %s" msgstr "" -#: includes/class-opentrust-cpt.php:557 +#: includes/class-ettic-otc-cpt.php:553 msgid "Regular saves update the current version. Use the checkbox below to formally publish a new version." msgstr "" -#: includes/class-opentrust-cpt.php:566 +#: includes/class-ettic-otc-cpt.php:562 msgid "Publish as new version" msgstr "" #. translators: %1$d: current version number, %2$d: next version number -#: includes/class-opentrust-cpt.php:571 +#: includes/class-ettic-otc-cpt.php:567 #, php-format msgid "This will save the current content as v%1$d and create v%2$d. Only check this for formal, published changes — not minor edits." msgstr "" -#: includes/class-opentrust-cpt.php:580 +#: includes/class-ettic-otc-cpt.php:576 msgid "What changed?" msgstr "" -#: includes/class-opentrust-cpt.php:583 +#: includes/class-ettic-otc-cpt.php:579 msgid "e.g., Updated data retention from 90 to 60 days" msgstr "" -#: includes/class-opentrust-cpt.php:584 +#: includes/class-ettic-otc-cpt.php:580 msgid "Shown in the public version history." msgstr "" -#: includes/class-opentrust-cpt.php:590 +#: includes/class-ettic-otc-cpt.php:586 msgid "Policy ID" msgstr "" -#: includes/class-opentrust-cpt.php:591 +#: includes/class-ettic-otc-cpt.php:587 msgid "e.g., POL-012" msgstr "" -#: includes/class-opentrust-cpt.php:592 +#: includes/class-ettic-otc-cpt.php:588 msgid "Optional short reference (e.g., POL-012). Shown on the public listing and in security questionnaires." msgstr "" -#: includes/class-opentrust-cpt.php:596 -#: includes/class-opentrust-cpt.php:1065 +#: includes/class-ettic-otc-cpt.php:592 +#: includes/class-ettic-otc-cpt.php:1061 #: templates/partials/policies.php:55 msgid "Category" msgstr "" -#: includes/class-opentrust-cpt.php:605 +#: includes/class-ettic-otc-cpt.php:601 msgid "Effective Date" msgstr "" -#: includes/class-opentrust-cpt.php:610 +#: includes/class-ettic-otc-cpt.php:606 msgid "Next Review Date" msgstr "" -#: includes/class-opentrust-cpt.php:615 +#: includes/class-ettic-otc-cpt.php:611 msgid "Framework Citations" msgstr "" -#: includes/class-opentrust-cpt.php:626 +#: includes/class-ettic-otc-cpt.php:622 msgid "e.g., SOC 2 CC6.1, ISO 27001 A.9.2…" msgstr "" -#: includes/class-opentrust-cpt.php:628 +#: includes/class-ettic-otc-cpt.php:624 msgid "Framework or control references this policy satisfies. Appears as pill badges on the public page." msgstr "" -#: includes/class-opentrust-cpt.php:632 +#: includes/class-ettic-otc-cpt.php:628 msgid "PDF Attachment" msgstr "" -#: includes/class-opentrust-cpt.php:638 +#: includes/class-ettic-otc-cpt.php:634 msgid "Replace PDF" msgstr "" -#: includes/class-opentrust-cpt.php:638 +#: includes/class-ettic-otc-cpt.php:634 msgid "Upload PDF" msgstr "" -#: includes/class-opentrust-cpt.php:640 +#: includes/class-ettic-otc-cpt.php:636 msgid "Upload the signed PDF. Visitors see a \"Download PDF\" button only when a file is attached." msgstr "" -#: includes/class-opentrust-cpt.php:644 -#: includes/class-opentrust-cpt.php:800 +#: includes/class-ettic-otc-cpt.php:640 +#: includes/class-ettic-otc-cpt.php:796 msgid "Sort Order" msgstr "" -#: includes/class-opentrust-cpt.php:646 -#: includes/class-opentrust-cpt.php:802 +#: includes/class-ettic-otc-cpt.php:642 +#: includes/class-ettic-otc-cpt.php:798 msgid "Lower numbers appear first." msgstr "" -#: includes/class-opentrust-cpt.php:663 -#: includes/class-opentrust-cpt.php:734 -#: includes/class-opentrust-cpt.php:1096 +#: includes/class-ettic-otc-cpt.php:659 +#: includes/class-ettic-otc-cpt.php:730 +#: includes/class-ettic-otc-cpt.php:1092 #: templates/partials/data-practices.php:96 #: templates/partials/subprocessors.php:37 msgid "Purpose" msgstr "" -#: includes/class-opentrust-cpt.php:665 +#: includes/class-ettic-otc-cpt.php:661 msgid "What does this subprocessor do for your company?" msgstr "" -#: includes/class-opentrust-cpt.php:669 +#: includes/class-ettic-otc-cpt.php:665 #: templates/partials/subprocessors.php:38 msgid "Data Processed" msgstr "" -#: includes/class-opentrust-cpt.php:671 +#: includes/class-ettic-otc-cpt.php:667 msgid "What types of data does this subprocessor handle?" msgstr "" -#: includes/class-opentrust-cpt.php:675 +#: includes/class-ettic-otc-cpt.php:671 msgid "Country / Location" msgstr "" -#: includes/class-opentrust-cpt.php:676 +#: includes/class-ettic-otc-cpt.php:672 msgid "e.g., United States" msgstr "" -#: includes/class-opentrust-cpt.php:680 +#: includes/class-ettic-otc-cpt.php:676 #: templates/partials/subprocessors.php:41 msgid "Website" msgstr "" -#: includes/class-opentrust-cpt.php:687 +#: includes/class-ettic-otc-cpt.php:683 msgid "DPA Signed" msgstr "" -#: includes/class-opentrust-cpt.php:689 +#: includes/class-ettic-otc-cpt.php:685 msgid "A Data Processing Agreement (DPA) is a contract between you and the subprocessor covering how they handle personal data on your behalf. Check this box once your organization has signed one with this vendor." msgstr "" -#: includes/class-opentrust-cpt.php:719 +#: includes/class-ettic-otc-cpt.php:715 msgid "Data Items Collected" msgstr "" -#: includes/class-opentrust-cpt.php:728 -#: includes/class-opentrust-cpt.php:766 +#: includes/class-ettic-otc-cpt.php:724 +#: includes/class-ettic-otc-cpt.php:762 msgid "Type and press Enter..." msgstr "" -#: includes/class-opentrust-cpt.php:741 +#: includes/class-ettic-otc-cpt.php:737 #: templates/partials/data-practices.php:103 msgid "Legal Basis" msgstr "" -#: includes/class-opentrust-cpt.php:743 +#: includes/class-ettic-otc-cpt.php:739 msgid "— Select —" msgstr "" -#: includes/class-opentrust-cpt.php:750 +#: includes/class-ettic-otc-cpt.php:746 msgid "Retention Period" msgstr "" -#: includes/class-opentrust-cpt.php:751 +#: includes/class-ettic-otc-cpt.php:747 msgid "e.g., 30 days" msgstr "" -#: includes/class-opentrust-cpt.php:757 +#: includes/class-ettic-otc-cpt.php:753 #: templates/partials/data-practices.php:117 msgid "Shared With" msgstr "" -#: includes/class-opentrust-cpt.php:772 +#: includes/class-ettic-otc-cpt.php:768 msgid "Properties" msgstr "" -#: includes/class-opentrust-cpt.php:776 +#: includes/class-ettic-otc-cpt.php:772 msgid "Collected" msgstr "" -#: includes/class-opentrust-cpt.php:780 +#: includes/class-ettic-otc-cpt.php:776 msgid "Stored" msgstr "" -#: includes/class-opentrust-cpt.php:784 +#: includes/class-ettic-otc-cpt.php:780 msgid "Shared with third parties" msgstr "" -#: includes/class-opentrust-cpt.php:788 +#: includes/class-ettic-otc-cpt.php:784 msgid "Sold to third parties" msgstr "" -#: includes/class-opentrust-cpt.php:792 +#: includes/class-ettic-otc-cpt.php:788 msgid "Encrypted" msgstr "" -#: includes/class-opentrust-cpt.php:795 +#: includes/class-ettic-otc-cpt.php:791 msgid "Unchecked means an explicit \"No\". The AI assistant reports these values verbatim to visitors asking questions like \"Do you sell customer data?\"." msgstr "" -#: includes/class-opentrust-cpt.php:1064 +#: includes/class-ettic-otc-cpt.php:1060 #: templates/partials/policies.php:52 msgid "ID" msgstr "" -#: includes/class-opentrust-cpt.php:1066 -#: includes/class-opentrust-version.php:160 +#: includes/class-ettic-otc-cpt.php:1062 +#: includes/class-ettic-otc-version.php:160 #: templates/partials/policies.php:56 msgid "Version" msgstr "" -#: includes/class-opentrust-cpt.php:1067 +#: includes/class-ettic-otc-cpt.php:1063 msgid "PDF" msgstr "" -#: includes/class-opentrust-cpt.php:1097 +#: includes/class-ettic-otc-cpt.php:1093 #: templates/partials/subprocessors.php:39 msgid "Location" msgstr "" -#: includes/class-opentrust-cpt.php:1098 +#: includes/class-ettic-otc-cpt.php:1094 #: templates/partials/subprocessors.php:40 msgid "DPA" msgstr "" -#: includes/class-opentrust-cpt.php:1117 +#: includes/class-ettic-otc-cpt.php:1113 msgid "Data Items" msgstr "" -#: includes/class-opentrust-cpt.php:1118 -#: includes/class-opentrust-cpt.php:1187 +#: includes/class-ettic-otc-cpt.php:1114 +#: includes/class-ettic-otc-cpt.php:1183 msgid "Order" msgstr "" -#: includes/class-opentrust-cpt.php:1147 +#: includes/class-ettic-otc-cpt.php:1143 msgid "Related Policy" msgstr "" -#: includes/class-opentrust-cpt.php:1149 +#: includes/class-ettic-otc-cpt.php:1145 msgid "— None —" msgstr "" -#: includes/class-opentrust-cpt.php:1154 +#: includes/class-ettic-otc-cpt.php:1150 msgid "Optional — link this answer to a published policy for deeper context." msgstr "" -#: includes/class-opentrust-cpt.php:1159 +#: includes/class-ettic-otc-cpt.php:1155 msgid "Sort order:" msgstr "" -#: includes/class-opentrust-cpt.php:1160 +#: includes/class-ettic-otc-cpt.php:1156 msgid "Use the Page Attributes box below (Order field) to control FAQ order. Lower numbers appear first." msgstr "" -#: includes/class-opentrust-io.php:193 +#: includes/class-ettic-otc-io.php:193 msgid "PHP ZipArchive extension is required for export." msgstr "" -#: includes/class-opentrust-io.php:198 +#: includes/class-ettic-otc-io.php:198 msgid "Could not create temp file for export." msgstr "" -#: includes/class-opentrust-io.php:212 +#: includes/class-ettic-otc-io.php:212 msgid "Could not open ZIP for writing." msgstr "" -#: includes/class-opentrust-io.php:240 +#: includes/class-ettic-otc-io.php:240 msgid "Unrecognised export format." msgstr "" #. translators: %1$d: schema version found, %2$d: schema version expected -#: includes/class-opentrust-io.php:246 +#: includes/class-ettic-otc-io.php:246 #, php-format msgid "Schema version mismatch (found %1$d, expected %2$d)." msgstr "" #. translators: %1$s: their version, %2$s: our version -#: includes/class-opentrust-io.php:257 +#: includes/class-ettic-otc-io.php:257 #, php-format msgid "Plugin major version mismatch (export: %1$s, this site: %2$s)." msgstr "" -#: includes/class-opentrust-io.php:396 +#: includes/class-ettic-otc-io.php:396 msgid "PHP ZipArchive extension is required." msgstr "" -#: includes/class-opentrust-io.php:400 +#: includes/class-ettic-otc-io.php:400 msgid "Could not open uploaded archive." msgstr "" -#: includes/class-opentrust-io.php:405 +#: includes/class-ettic-otc-io.php:405 msgid "Archive is missing manifest.json." msgstr "" -#: includes/class-opentrust-io.php:409 +#: includes/class-ettic-otc-io.php:409 msgid "manifest.json could not be parsed." msgstr "" -#: includes/class-opentrust-io.php:697 +#: includes/class-ettic-otc-io.php:692 msgid "Could not reopen archive for media import." msgstr "" #. translators: %s: media path -#: includes/class-opentrust-io.php:712 +#: includes/class-ettic-otc-io.php:707 #, php-format msgid "Bundled media missing during import: %s" msgstr "" #. translators: %s: filename -#: includes/class-opentrust-io.php:732 +#: includes/class-ettic-otc-io.php:727 #, php-format msgid "Could not write attachment file: %s" msgstr "" -#: includes/class-opentrust-io.php:750 +#: includes/class-ettic-otc-io.php:745 msgid "Could not create attachment." msgstr "" -#: includes/class-opentrust-render.php:83 +#: includes/class-ettic-otc-render.php:83 msgid "Session expired. Please reload the page and try again." msgstr "" -#: includes/class-opentrust-render.php:89 +#: includes/class-ettic-otc-render.php:89 msgid "Please enter a question." msgstr "" -#: includes/class-opentrust-render.php:98 +#: includes/class-ettic-otc-render.php:98 msgid "AI chat is not configured." msgstr "" -#: includes/class-opentrust-render.php:270 +#: includes/class-ettic-otc-render.php:270 msgid "Page not found." msgstr "" -#: includes/class-opentrust-render.php:271 +#: includes/class-ettic-otc-render.php:271 #: templates/partials/policy-single.php:54 msgid "Back to Trust Center" msgstr "" -#: includes/class-opentrust-render.php:442 +#: includes/class-ettic-otc-render.php:442 msgid "Updated just now" msgstr "" #. translators: %d: number of minutes since last update -#: includes/class-opentrust-render.php:447 +#: includes/class-ettic-otc-render.php:447 #, php-format msgid "Updated %d minute ago" msgid_plural "Updated %d minutes ago" @@ -1789,7 +1792,7 @@ msgstr[0] "" msgstr[1] "" #. translators: %d: number of hours since last update -#: includes/class-opentrust-render.php:454 +#: includes/class-ettic-otc-render.php:454 #, php-format msgid "Updated %d hour ago" msgid_plural "Updated %d hours ago" @@ -1797,7 +1800,7 @@ msgstr[0] "" msgstr[1] "" #. translators: %d: number of days since last update -#: includes/class-opentrust-render.php:461 +#: includes/class-ettic-otc-render.php:461 #, php-format msgid "Updated %d day ago" msgid_plural "Updated %d days ago" @@ -1806,108 +1809,108 @@ msgstr[1] "" #. translators: %s = formatted date #. translators: %s: policy last updated date -#: includes/class-opentrust-render.php:467 +#: includes/class-ettic-otc-render.php:467 #: templates/partials/policy-single.php:111 #, php-format msgid "Updated %s" msgstr "" -#: includes/class-opentrust-render.php:511 +#: includes/class-ettic-otc-render.php:511 msgid "Security" msgstr "" -#: includes/class-opentrust-render.php:512 +#: includes/class-ettic-otc-render.php:512 msgid "Privacy" msgstr "" -#: includes/class-opentrust-render.php:513 +#: includes/class-ettic-otc-render.php:513 msgid "Compliance" msgstr "" -#: includes/class-opentrust-render.php:514 +#: includes/class-ettic-otc-render.php:514 msgid "Operational" msgstr "" -#: includes/class-opentrust-render.php:526 +#: includes/class-ettic-otc-render.php:526 msgid "Certified" msgstr "" -#: includes/class-opentrust-render.php:527 +#: includes/class-ettic-otc-render.php:527 msgid "In audit" msgstr "" -#: includes/class-opentrust-render.php:528 +#: includes/class-ettic-otc-render.php:528 msgid "Expired" msgstr "" -#: includes/class-opentrust-render.php:537 +#: includes/class-ettic-otc-render.php:537 msgid "Compliant" msgstr "" -#: includes/class-opentrust-render.php:538 +#: includes/class-ettic-otc-render.php:538 msgid "Working toward" msgstr "" -#: includes/class-opentrust-render.php:539 +#: includes/class-ettic-otc-render.php:539 msgid "Lapsed" msgstr "" -#: includes/class-opentrust-render.php:545 +#: includes/class-ettic-otc-render.php:545 msgid "Consent" msgstr "" -#: includes/class-opentrust-render.php:546 +#: includes/class-ettic-otc-render.php:546 msgid "Contractual Necessity" msgstr "" -#: includes/class-opentrust-render.php:547 +#: includes/class-ettic-otc-render.php:547 msgid "Legitimate Interest" msgstr "" -#: includes/class-opentrust-render.php:548 +#: includes/class-ettic-otc-render.php:548 msgid "Legal Obligation" msgstr "" -#: includes/class-opentrust-render.php:549 +#: includes/class-ettic-otc-render.php:549 msgid "Vital Interest" msgstr "" -#: includes/class-opentrust-render.php:550 +#: includes/class-ettic-otc-render.php:550 msgid "Public Interest" msgstr "" -#: includes/class-opentrust-version.php:127 +#: includes/class-ettic-otc-version.php:127 msgid "Version History" msgstr "" -#: includes/class-opentrust-version.php:149 +#: includes/class-ettic-otc-version.php:149 msgid "Current version:" msgstr "" -#: includes/class-opentrust-version.php:152 +#: includes/class-ettic-otc-version.php:152 msgid "Version history will appear after the first update." msgstr "" -#: includes/class-opentrust-version.php:162 +#: includes/class-ettic-otc-version.php:162 #: templates/partials/policies.php:58 msgid "Actions" msgstr "" -#: includes/class-opentrust-version.php:169 +#: includes/class-ettic-otc-version.php:169 #: templates/partials/policy-single.php:174 msgid "Current" msgstr "" -#: includes/class-opentrust-version.php:183 -#: includes/class-opentrust-version.php:184 +#: includes/class-ettic-otc-version.php:183 +#: includes/class-ettic-otc-version.php:184 msgid "View" msgstr "" -#: includes/class-opentrust-version.php:187 +#: includes/class-ettic-otc-version.php:187 msgid "Compare" msgstr "" -#: includes/class-opentrust-version.php:188 +#: includes/class-ettic-otc-version.php:188 msgid "Diff" msgstr "" @@ -1991,170 +1994,170 @@ msgstr "" msgid "A data practice describes a specific way a company collects, uses, stores, or shares information. Each practice usually spells out what data is involved, why it is collected, how long it is kept, and who it is shared with. Grouping data practices by category, such as account data, usage data, or support data, helps customers understand exactly what happens to their information." msgstr "" -#: includes/providers/class-opentrust-chat-provider-anthropic.php:44 -#: includes/providers/class-opentrust-chat-provider.php:46 +#: includes/providers/class-ettic-otc-chat-provider-anthropic.php:44 +#: includes/providers/class-ettic-otc-chat-provider.php:46 msgid "Anthropic" msgstr "" -#: includes/providers/class-opentrust-chat-provider-anthropic.php:63 +#: includes/providers/class-ettic-otc-chat-provider-anthropic.php:63 msgid "No models available — your account may not be authorized." msgstr "" -#: includes/providers/class-opentrust-chat-provider-anthropic.php:127 +#: includes/providers/class-ettic-otc-chat-provider-anthropic.php:127 msgid "Anthropic adapter missing required args." msgstr "" -#: includes/providers/class-opentrust-chat-provider-anthropic.php:219 +#: includes/providers/class-ettic-otc-chat-provider-anthropic.php:219 msgid "Anthropic request failed." msgstr "" -#: includes/providers/class-opentrust-chat-provider-anthropic.php:414 +#: includes/providers/class-ettic-otc-chat-provider-anthropic.php:414 msgid "Searching documents…" msgstr "" -#: includes/providers/class-opentrust-chat-provider-anthropic.php:415 +#: includes/providers/class-ettic-otc-chat-provider-anthropic.php:415 msgid "Reading documents…" msgstr "" -#: includes/providers/class-opentrust-chat-provider-openai.php:66 -#: includes/providers/class-opentrust-chat-provider.php:52 +#: includes/providers/class-ettic-otc-chat-provider-openai.php:66 +#: includes/providers/class-ettic-otc-chat-provider.php:52 msgid "OpenAI" msgstr "" -#: includes/providers/class-opentrust-chat-provider-openai.php:166 +#: includes/providers/class-ettic-otc-chat-provider-openai.php:166 msgid "OpenAI adapter missing required args." msgstr "" -#: includes/providers/class-opentrust-chat-provider-openai.php:253 +#: includes/providers/class-ettic-otc-chat-provider-openai.php:253 msgid "OpenAI request failed." msgstr "" -#: includes/providers/class-opentrust-chat-provider-openrouter.php:38 -#: includes/providers/class-opentrust-chat-provider.php:58 +#: includes/providers/class-ettic-otc-chat-provider-openrouter.php:38 +#: includes/providers/class-ettic-otc-chat-provider.php:58 msgid "OpenRouter" msgstr "" -#: includes/providers/class-opentrust-chat-provider.php:104 +#: includes/providers/class-ettic-otc-chat-provider.php:104 msgid "No chat models available for this key." msgstr "" -#: includes/providers/class-opentrust-chat-provider.php:117 +#: includes/providers/class-ettic-otc-chat-provider.php:117 msgid "API key is empty." msgstr "" -#: includes/providers/class-opentrust-chat-provider.php:123 +#: includes/providers/class-ettic-otc-chat-provider.php:123 msgid "Request failed." msgstr "" -#: includes/providers/class-opentrust-chat-provider.php:268 +#: includes/providers/class-ettic-otc-chat-provider.php:268 msgid "I couldn't find a confident answer in the published trust center documents. Please contact the team for help." msgstr "" #. translators: %s is the document title. -#: includes/providers/class-opentrust-chat-provider.php:342 +#: includes/providers/class-ettic-otc-chat-provider.php:342 #, php-format msgid "Read \"%s\"" msgstr "" #. translators: %s is the document title. -#: includes/providers/class-opentrust-chat-provider.php:344 +#: includes/providers/class-ettic-otc-chat-provider.php:344 #, php-format msgid "Reading \"%s\"" msgstr "" #. translators: %s is the document id. -#: includes/providers/class-opentrust-chat-provider.php:350 +#: includes/providers/class-ettic-otc-chat-provider.php:350 #, php-format msgid "Read %s" msgstr "" #. translators: %s is the document id. -#: includes/providers/class-opentrust-chat-provider.php:352 +#: includes/providers/class-ettic-otc-chat-provider.php:352 #, php-format msgid "Reading %s" msgstr "" -#: includes/providers/class-opentrust-chat-provider.php:354 +#: includes/providers/class-ettic-otc-chat-provider.php:354 msgid "Read a document" msgstr "" -#: includes/providers/class-opentrust-chat-provider.php:354 +#: includes/providers/class-ettic-otc-chat-provider.php:354 msgid "Reading a document" msgstr "" #. translators: %s is the search query. -#: includes/providers/class-opentrust-chat-provider.php:367 +#: includes/providers/class-ettic-otc-chat-provider.php:367 #, php-format msgid "Searched for \"%s\"" msgstr "" #. translators: %s is the search query. -#: includes/providers/class-opentrust-chat-provider.php:369 +#: includes/providers/class-ettic-otc-chat-provider.php:369 #, php-format msgid "Searching for \"%s\"" msgstr "" -#: includes/providers/class-opentrust-chat-provider.php:371 +#: includes/providers/class-ettic-otc-chat-provider.php:371 msgid "Searched documents" msgstr "" -#: includes/providers/class-opentrust-chat-provider.php:371 +#: includes/providers/class-ettic-otc-chat-provider.php:371 msgid "Searching documents" msgstr "" #. translators: %d is the number of documents that were read in parallel. -#: includes/providers/class-opentrust-chat-provider.php:399 +#: includes/providers/class-ettic-otc-chat-provider.php:399 #, php-format msgid "Read %d documents" msgstr "" #. translators: %d is the number of documents being read in parallel. -#: includes/providers/class-opentrust-chat-provider.php:401 +#: includes/providers/class-ettic-otc-chat-provider.php:401 #, php-format msgid "Reading %d documents" msgstr "" #. translators: %d is the number of search queries that were fired in parallel. -#: includes/providers/class-opentrust-chat-provider.php:406 +#: includes/providers/class-ettic-otc-chat-provider.php:406 #, php-format msgid "Ran %d searches" msgstr "" #. translators: %d is the number of search queries fired in parallel. -#: includes/providers/class-opentrust-chat-provider.php:408 +#: includes/providers/class-ettic-otc-chat-provider.php:408 #, php-format msgid "Running %d searches" msgstr "" #. translators: %d is the number of parallel retrieval calls (mixed types). -#: includes/providers/class-opentrust-chat-provider.php:412 +#: includes/providers/class-ettic-otc-chat-provider.php:412 #, php-format msgid "Ran %d retrievals" msgstr "" #. translators: %d is the number of parallel retrieval calls (mixed types). -#: includes/providers/class-opentrust-chat-provider.php:414 +#: includes/providers/class-ettic-otc-chat-provider.php:414 #, php-format msgid "Running %d retrievals" msgstr "" -#: includes/providers/class-opentrust-chat-provider.php:443 -#: includes/providers/class-opentrust-chat-provider.php:462 -#: includes/providers/class-opentrust-chat-provider.php:513 +#: includes/providers/class-ettic-otc-chat-provider.php:443 +#: includes/providers/class-ettic-otc-chat-provider.php:462 +#: includes/providers/class-ettic-otc-chat-provider.php:513 msgid "Refused outbound request to disallowed host." msgstr "" -#: includes/providers/class-opentrust-chat-provider.php:518 +#: includes/providers/class-ettic-otc-chat-provider.php:518 msgid "AI streaming requires the PHP cURL extension." msgstr "" -#: includes/providers/class-opentrust-chat-provider.php:620 +#: includes/providers/class-ettic-otc-chat-provider.php:620 msgid "AI streaming requires the WordPress cURL transport." msgstr "" #. translators: %d: HTTP status code returned by the provider -#: includes/providers/class-opentrust-chat-provider.php:673 -#: includes/providers/class-opentrust-chat-provider.php:728 +#: includes/providers/class-ettic-otc-chat-provider.php:673 +#: includes/providers/class-ettic-otc-chat-provider.php:728 #, php-format msgid "Provider returned HTTP %d" msgstr "" @@ -2578,5 +2581,5 @@ msgid "© %1$s %2$s. All rights reserved." msgstr "" #: templates/trust-center.php:220 -msgid "Powered by OpenTrust" +msgid "Powered by Open Trust Center" msgstr "" diff --git a/languages/opentrust-nl_NL.mo b/languages/opentrust-nl_NL.mo deleted file mode 100644 index de08d279a58e725b5c6823180f5adb391adf14c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9334 zcmb7|TZ|;vS;tRehd7%H#0iO=IL>kG@r7*n?vB@&%zC|^nH{gkdmDRijxTYlyUtYC zbahp`s(Qw=0mo8^g(9MGagacXkWh#)i3CUp34+j!X%o6wtxF3Aa z9%FtHJPbzQiw$1)Zeuj%8SrPo=fG>gFM}TjzuEME2fUf*?}7)wAA=tRuYZp*SAn;K z?*s1vKMEcP8DbJp>sKJ8n9qR+!7qYZ|3&ax@KsRz{}{Xy{0YdB%U=){Zvg)t)OzoQhy?sF_%Qf+ z@NV!`@GkJ(YqudI-thopyrQ2(eX=7|8Ies_jM4~ncoAo{vU%n_lw{z_;;Y> zzkYRC_Ze`&^OwLC@OAJO@X!a0xfSe!;`6V9qT{#0o5A02-oFg)<@vur$@dd%rg1G$ zbbbm{|1!wWoZwIT7J+*IIZ)%j0P-_mY5KnbYTa*x*Mt8IejI!qlwMx*^MS9|fztOQ zp!oh6C_coX#-$AoK*`}L@GstG%=6&AJa1qGw}W2+e;s@YEWvXy_j&Mpp!og-LMyaCkwXTVQ^Ujk7r^EaTz|05{6{X042X3D0vM)o%h$k6#O0VG4M*1LUQ{oco2LZwBYwao&QIm^yPoR z1@L1$w82$S=Pw)FZTg=Dwa*`c+W*f%@$);N#=i_|-G2Zz?gyak^FKlH;lCSvyA9`h zAE@(u2-N&GsPoN zlJ7MzOSk|^{}w^PB=7w4nAs1WJy_K)t^J z>Kp|qzVCqI@3$L#6}*Dy*Fi*X-T)DSx%Q?o?`}~1y${s5wFcM0TX{YSz75oMf_4uL z(#+dwx;{g@n|3el0_`r^Cux1!8Je#9X%Enj(H^8>>OST^1?rN%>B?v&jV(Qo0na;~ z8#SA|HhGf#&o{k8P<$O3TAN*Rj3auhZT^J4wSt&8KO)aO>WFZUm33W8uI} zmF-299S!5CcCoE{&TbZ2R_vsCVuwYRc6V)&+hSDOx*S!t?Yg{n<&s&5?Q*wHx1C*e zWu0!O-Kb8B{H^*cvurDuZMJ$v#YTH=F?4yWV%@HrTbb=kI~;YgwCah5%5_I&TJHv8 zQdjM@)u=Npi>|AxqU5nVyFbrS9$QWm*-O+dEKU!t=(W)lu?;xyLOaE+fkZD zoy@iEM&_bQbnMzFiPGHii|nS`v4b=p)vmG-)hUY|28k67eK4$Bz>d7u4z0xHuJmk- z@@mJGZF{PyZRV0FgXrcQoV;Y#V3?&*&e@}Q8xq_0yereqW_#EyK?LqpHtH1HjvY8m zk;6#OcC%bMyIYLxnbWIwak654#4J~RyHMHJo_*e)^&(sKBJ=&r>mFEfR5R$7YC@N1 z+mx;_EZ?oY5W;w!e0+>chQIdgH_b}a?c2JT-*gpzBt^Mv=Cq``=5=5_17rL z^jNiv2KKe*euFo|)Ww2bb97@_&7MhC&C>_8Zio%?Y7N&Za2yz@rPN@x1%hLp;cNgWh~t$Z+c#}hf#v+W2h68)9f&# zbWe>OGBWE`HG*Wgr8_x;l_K6XCnD_QTyR+CgsjW1L{(au6KURuATPHQMdOc7M!EKy zXPJDA*l-fI>#cl4QJ@-m(l)1}fitHH9ZjYU-SwzM?zXe*X&)4^%i88N4$SMCISr5G zY4C;fzUUGov704J?-XUfvauUr%eCBv=P{NyNb7<2gTuJDTFSzay_(CNu_OCTJ1td2nSKRWRyiE{;qV}soUWc;(Fum+oo}R-JZjC{Z?t-DV`35!@(bV0$h zZRad&ksh;Arg?2PM&+=moWap>5Jko_E-Je{pb2P`rO&uLHfMUsEBwdyLRvF0c$+hr zATi9GsiRWV=0qg~vhB($L|k6fBfT$%=FDtp)RVkphjqty(yqo)n6teIgHa5TJv6Sg zqr)?3&gjRkWwR^>GMsV1Y!u@%z8G8SN`L%n=tgH$*SP48BeiI=v$KR`)O;J~QBF-P z%B?HQg3x(sNY*4YkM$I5xG&?@5RUBPyh?>oIX=YQWCkGvXfl_MLmfBC3}oPT2j)s& zagxIzBtq;sXMiO!8ZP;l&PgwjD7#g2JeR{rTXpcEtGKF)woWx61O^icw>cSr{7-*Ue?dS5b^qgrtqg_xIq=cfl zq>Ize_x0rDFVpv?fgu^Xbm%xmnp>e7Z|b8R$&C(f8k9>P-@@9O{J`G25Z`9b2g&m`@iYHScldWu-q2J+rcXOmcq0 z2I|K?82(7^Tgt8TV#ny@bmqUwq4FLTc$~`t}qyBy^G~-iY?C9T8~=| zOPA~ll8b_Q_v9R6nC;#-nca@v_Ps2TCnMr* z>nvH;l07=AVe74@9L88?2&lSk&&l`xNw*S0 zcG)L<4gH8&qo0&uZYJ-bh{%(14fduNE;noBiWgOfB~F#td>w|))+CBMF0WMPm7@VP z;mkywPdrF(n7@q|>acj4rKm_!1#*2|#tI@BbD!2_o+hU8OI*S{99$Xo>vXH{2X(tan36b;Iv+_HsL(cam_af+V-S)Rn64;DgFK7pgnAX&z0tw0oAN zE>w7}@pe>r=gTNcJTJ5~ssEd5y)c4}DEPuX*=FFJcApAQQW>vIo-WZYD3@@V)%mym zPM+hQp>H|U2W3}|5}PBixgyLoHDKx{RbQhLmp)SlPH8bK@W^)Y<>;JQadDY$ZBmZ~ zrq}drQzfK{-6Cg;@`1}_>_K5??W8qMUYfJvCCPEZSZ>QgT8PUG3Pk$Q(S}FNDZ;;3 z8P$i_-vHH<`pvL_FBwg>c+B-xcc3`tI5#hSOEizm#sZthFS1W;jx`n#qT2YWF&o(~ zFC*9U1TR`q5sYx5$ZD;HU!j!r5UG;X8kt;gxG9F7eumOd&g`d}(|HX; z66^fDhI>f-ViA{-bgDPX=fo&?krhSJlqmC8VK|OSErKXqV^@IvqZr}6=*at5Af2Lnl_0xQ3fWCxdCsm zw7C*g-cB_rMlmTuXB_X;tXeZgD1lrOPxC|6pQZTop#-bFWb_I< zp%6V^WR&iyUi$iTkXD^?l=kK9<%%z>1T&LnsUOd2oAU({n>xUhgHO7G<~4@n4GvP< z)OE@;C2290q!{mDUwYxC7jR;s@J#uLcOjCnIYm$dY*GGe9KNPIGCAWD$coPd#&EJ= zZw0r6qL&C70++G~g{xVc^o8j1W?YW?xE(x*%UEOw*No~6h%M$(be}gXkTM^~B+>^KJ6g^pad8gbmFQy?LZKxb`$m=6eI4O-exU$HnD*`cVk><`W#d zT#)BSzBfb{JZ_Anq_X2zWu@TD=KW%zwb+T|rD3rRh9#%rQ-F@cFeb|6dE{+InmG0y z;dpopmaU*Gk$3j9W=oZE8Op5rbODDA*XU$=lPg|Yi>5W+f?$n~D-(@LRZv@$Xx7-9 zH}qZp-H4L(|NBOTD4(@2KP^IA(Rual;m9SOY`x76&urJqh^sN|2$$IOt;K~ z(gS7IO{ondyx;NFYg5^d4>sXvQ`}xGwnmisW`K7zZ&};wYbDMRdZoF1vnfUp-!}gT DZf`j# diff --git a/languages/opentrust-nl_NL.po b/languages/opentrust-nl_NL.po deleted file mode 100644 index bc09e36..0000000 --- a/languages/opentrust-nl_NL.po +++ /dev/null @@ -1,2496 +0,0 @@ -# Copyright (C) 2026 OpenTrust. Licensed under GPL-2.0-or-later. -msgid "" -msgstr "" -"Project-Id-Version: OpenTrust 1.0.0\n" -"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/opentrust\n" -"Last-Translator: OpenTrust bundled starter \n" -"Language-Team: Dutch (Netherlands)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2026-04-14T22:04:10+00:00\n" -"PO-Revision-Date: 2026-04-14 21:55+0000\n" -"Language: nl_NL\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: WP-CLI 2.12.0\n" -"X-Domain: opentrust\n" - -#. Plugin Name of the plugin -#. Author of the plugin -#: opentrust.php -#: includes/class-opentrust-admin.php:47 -#: includes/class-opentrust-admin.php:48 -#, fuzzy -msgid "OpenTrust" -msgstr "OpenTrust" - -#. Plugin URI of the plugin -#: opentrust.php -msgid "https://github.com/opentrust/opentrust" -msgstr "" - -#. Description of the plugin -#: opentrust.php -#, fuzzy -msgid "A self-hosted, open-source trust center for publishing security policies, subprocessors, certifications, and data practices." -msgstr "Een zelf-gehost, open-source vertrouwenscentrum voor het publiceren van beveiligingsbeleid, subverwerkers, certificeringen en gegevenspraktijken." - -#. Author URI of the plugin -#: opentrust.php -msgid "https://github.com/opentrust" -msgstr "" - -#: includes/class-opentrust-admin.php:58 -#: includes/class-opentrust-admin.php:59 -msgid "Settings" -msgstr "" - -#: includes/class-opentrust-admin.php:67 -#: includes/class-opentrust-admin.php:68 -#: includes/class-opentrust-admin.php:632 -msgid "Subscribers" -msgstr "" - -#: includes/class-opentrust-admin.php:76 -#: includes/class-opentrust-admin.php:77 -#: includes/class-opentrust-admin.php:1943 -msgid "Broadcast History" -msgstr "" - -#: includes/class-opentrust-admin.php:88 -#: includes/class-opentrust-admin.php:89 -msgid "Questions" -msgstr "" - -#: includes/class-opentrust-admin.php:111 -msgid "General Settings" -msgstr "" - -#: includes/class-opentrust-admin.php:116 -msgid "Endpoint Slug" -msgstr "" - -#: includes/class-opentrust-admin.php:117 -msgid "The URL path for your trust center (e.g., \"trust-center\" = yoursite.com/trust-center/)." -msgstr "" - -#: includes/class-opentrust-admin.php:120 -msgid "Page Title" -msgstr "" - -#: includes/class-opentrust-admin.php:122 -msgid "Company Name" -msgstr "" - -#: includes/class-opentrust-admin.php:124 -msgid "Tagline" -msgstr "" - -#: includes/class-opentrust-admin.php:125 -msgid "A short description displayed below the company name in the hero section." -msgstr "" - -#: includes/class-opentrust-admin.php:131 -msgid "Branding" -msgstr "" - -#: includes/class-opentrust-admin.php:136 -msgid "Logo" -msgstr "" - -#: includes/class-opentrust-admin.php:137 -msgid "AI Avatar" -msgstr "" - -#: includes/class-opentrust-admin.php:139 -msgid "Accent Color" -msgstr "" - -#: includes/class-opentrust-admin.php:140 -msgid "Used for buttons, links, and highlights. Choose a color that matches your brand." -msgstr "" - -#: includes/class-opentrust-admin.php:146 -msgid "Visible Sections" -msgstr "" - -#: includes/class-opentrust-admin.php:147 -msgid "Choose which sections to display on the trust center." -msgstr "" - -#: includes/class-opentrust-admin.php:151 -msgid "Sections" -msgstr "" - -#: includes/class-opentrust-admin.php:156 -msgid "Email Notifications" -msgstr "" - -#: includes/class-opentrust-admin.php:157 -msgid "Configure subscriber notifications for trust center updates." -msgstr "" - -#: includes/class-opentrust-admin.php:161 -msgid "Enable Notifications" -msgstr "" - -#: includes/class-opentrust-admin.php:162 -msgid "Show the subscribe form on the trust center and allow policy changes to be broadcast to subscribers." -msgstr "" - -#: includes/class-opentrust-admin.php:165 -msgid "From Name" -msgstr "" - -#: includes/class-opentrust-admin.php:166 -msgid "Sender name for notification emails. Defaults to company name." -msgstr "" - -#: includes/class-opentrust-admin.php:169 -msgid "Reply-To Email" -msgstr "" - -#: includes/class-opentrust-admin.php:170 -msgid "Reply-to address for notification emails. Defaults to admin email." -msgstr "" - -#: includes/class-opentrust-admin.php:176 -msgid "Spam Protection" -msgstr "" - -#: includes/class-opentrust-admin.php:177 -msgid "Protect the subscribe form from abuse with rate limiting and Cloudflare Turnstile." -msgstr "" - -#: includes/class-opentrust-admin.php:181 -msgid "Rate Limit" -msgstr "" - -#: includes/class-opentrust-admin.php:182 -msgid "Maximum subscribe attempts per IP address per hour. Set to 0 to disable." -msgstr "" - -#: includes/class-opentrust-admin.php:185 -msgid "Turnstile Site Key" -msgstr "" - -#: includes/class-opentrust-admin.php:186 -msgid "Public site key from your Cloudflare Turnstile widget. Leave blank to disable." -msgstr "" - -#: includes/class-opentrust-admin.php:189 -msgid "Turnstile Secret Key" -msgstr "" - -#: includes/class-opentrust-admin.php:190 -msgid "Secret key from Cloudflare Turnstile. Stored securely — never exposed to the frontend." -msgstr "" - -#: includes/class-opentrust-admin.php:249 -msgid "Low contrast on white backgrounds" -msgstr "" - -#: includes/class-opentrust-admin.php:250 -msgid "Using your exact color on white backgrounds" -msgstr "" - -#: includes/class-opentrust-admin.php:253 -msgid "Your chosen color is too light for buttons, links, and borders on white sections. On those surfaces OpenTrust will use a darker, on-brand variant:" -msgstr "" - -#: includes/class-opentrust-admin.php:256 -msgid "You've chosen to keep your exact color on white backgrounds. Buttons, links, and borders in those sections may be hard to read." -msgstr "" - -#: includes/class-opentrust-admin.php:268 -msgid "The hero and navigation still use your exact color." -msgstr "" - -#: includes/class-opentrust-admin.php:279 -msgid "Use my exact color anyway — skip the contrast adjustment." -msgstr "" - -#: includes/class-opentrust-admin.php:292 -msgid "Select Logo" -msgstr "" - -#: includes/class-opentrust-admin.php:293 -msgid "Used in the hero and sticky nav. A white version is recommended — it sits on a dark background." -msgstr "" - -#: includes/class-opentrust-admin.php:300 -msgid "Select Avatar" -msgstr "" - -#: includes/class-opentrust-admin.php:301 -msgid "Square image used as the avatar on AI chat responses. Use a colored background with a light or dark favicon or logo on top." -msgstr "" - -#: includes/class-opentrust-admin.php:316 -#: includes/class-opentrust-cpt.php:337 -#: includes/class-opentrust-cpt.php:509 -#: includes/class-opentrust-cpt.php:547 -msgid "Remove" -msgstr "" - -#: includes/class-opentrust-admin.php:328 -msgid "Enable email notifications" -msgstr "" - -#: includes/class-opentrust-admin.php:342 -msgid "per hour" -msgstr "" - -#: includes/class-opentrust-admin.php:357 -msgid "Enter secret key…" -msgstr "" - -#: includes/class-opentrust-admin.php:360 -msgid "Key saved" -msgstr "" - -#: includes/class-opentrust-admin.php:372 -#: templates/partials/certifications.php:21 -#, fuzzy -msgid "Certifications & Compliance" -msgstr "Certificeringen & compliance" - -#: includes/class-opentrust-admin.php:373 -#: includes/class-opentrust-cpt.php:65 -#: includes/class-opentrust-cpt.php:75 -#: templates/chat.php:44 -#: templates/partials/hero.php:55 -#: templates/trust-center.php:106 -#, fuzzy -msgid "Policies" -msgstr "Beleid" - -#: includes/class-opentrust-admin.php:374 -#: includes/class-opentrust-cpt.php:132 -#: includes/class-opentrust-cpt.php:141 -#: templates/chat.php:46 -#: templates/partials/hero.php:61 -#: templates/partials/subprocessors.php:20 -#: templates/trust-center.php:108 -#, fuzzy -msgid "Subprocessors" -msgstr "Subverwerkers" - -#: includes/class-opentrust-admin.php:375 -#: includes/class-opentrust-cpt.php:165 -#: includes/class-opentrust-cpt.php:174 -#: templates/chat.php:47 -#: templates/partials/data-practices.php:34 -#: templates/trust-center.php:109 -#, fuzzy -msgid "Data Practices" -msgstr "Gegevensverwerking" - -#: includes/class-opentrust-admin.php:501 -msgid "View Trust Center" -msgstr "" - -#: includes/class-opentrust-admin.php:508 -#: includes/class-opentrust-render.php:823 -msgid "General" -msgstr "" - -#: includes/class-opentrust-admin.php:512 -msgid "AI Chat" -msgstr "" - -#: includes/class-opentrust-admin.php:515 -msgid "Live" -msgstr "" - -#: includes/class-opentrust-admin.php:592 -msgid "This email is already in the subscriber list." -msgstr "" - -#: includes/class-opentrust-admin.php:596 -msgid "Subscriber added and marked as verified." -msgstr "" - -#: includes/class-opentrust-admin.php:597 -msgid "Could not add subscriber." -msgstr "" - -#: includes/class-opentrust-admin.php:611 -msgid "Subscriber deleted." -msgstr "" - -#: includes/class-opentrust-admin.php:619 -msgid "Subscriber verified. No confirmation email sent." -msgstr "" - -#: includes/class-opentrust-admin.php:621 -msgid "Could not verify subscriber." -msgstr "" - -#. translators: 1: imported, 2: updated, 3: skipped, 4: errors -#: includes/class-opentrust-admin.php:647 -#, php-format -msgid "Import complete: %1$d imported, %2$d updated, %3$d skipped, %4$d errors." -msgstr "" - -#: includes/class-opentrust-admin.php:656 -msgid "Show errors" -msgstr "" - -#. translators: %d: number of additional errors -#: includes/class-opentrust-admin.php:664 -#, php-format -msgid "… and %d more." -msgstr "" - -#: includes/class-opentrust-admin.php:676 -#: includes/class-opentrust-admin.php:710 -msgid "Add subscriber" -msgstr "" - -#: includes/class-opentrust-admin.php:681 -#: includes/class-opentrust-admin.php:805 -#, fuzzy -msgid "Email" -msgstr "E-mail" - -#: includes/class-opentrust-admin.php:685 -#: includes/class-opentrust-admin.php:806 -#: templates/partials/subprocessors.php:36 -#: templates/partials/subscribe.php:58 -#, fuzzy -msgid "Name" -msgstr "Naam" - -#: includes/class-opentrust-admin.php:686 -#: templates/partials/subscribe.php:60 -msgid "Jane Doe" -msgstr "" - -#: includes/class-opentrust-admin.php:689 -#: includes/class-opentrust-admin.php:807 -#: templates/partials/subscribe.php:64 -#, fuzzy -msgid "Company" -msgstr "Bedrijf" - -#: includes/class-opentrust-admin.php:690 -#: templates/partials/subscribe.php:66 -msgid "Acme Inc." -msgstr "" - -#: includes/class-opentrust-admin.php:694 -msgid "Notify about" -msgstr "" - -#: includes/class-opentrust-admin.php:707 -msgid "Mark as verified immediately (skip confirmation email)" -msgstr "" - -#: includes/class-opentrust-admin.php:714 -msgid "By default, the subscriber receives a confirmation email they must click to activate. Check \"Mark as verified\" to skip that step and activate them immediately — only do this when you have consent on file." -msgstr "" - -#: includes/class-opentrust-admin.php:728 -msgid "Import from CSV" -msgstr "" - -#: includes/class-opentrust-admin.php:735 -msgid "CSV file" -msgstr "" - -#: includes/class-opentrust-admin.php:739 -msgid "If email exists" -msgstr "" - -#: includes/class-opentrust-admin.php:741 -msgid "Skip existing (safest)" -msgstr "" - -#: includes/class-opentrust-admin.php:742 -msgid "Update — merge non-empty fields" -msgstr "" - -#: includes/class-opentrust-admin.php:743 -msgid "Replace — overwrite all fields" -msgstr "" - -#: includes/class-opentrust-admin.php:752 -msgid "Verify everyone on import" -msgstr "" - -#: includes/class-opentrust-admin.php:753 -msgid "Overrides the Status column in the CSV. Every row is set to active and no confirmation emails are sent. Uncheck to respect the CSV Status column — pending rows will remain pending and must be verified manually from the subscriber list." -msgstr "" - -#: includes/class-opentrust-admin.php:760 -msgid "Import CSV" -msgstr "" - -#: includes/class-opentrust-admin.php:763 -msgid "Download example CSV" -msgstr "" - -#: includes/class-opentrust-admin.php:768 -msgid "Required column: email. Optional: name, company, status, categories, subscribed, confirmed. Categories can be semicolon- or comma-separated. Maximum 5,000 rows, 2 MB file size. Confirmation emails are never sent on import." -msgstr "" - -#. translators: %d: total subscriber count -#: includes/class-opentrust-admin.php:780 -#, php-format -msgid "All (%d)" -msgstr "" - -#. translators: %d: active subscriber count -#: includes/class-opentrust-admin.php:787 -#, php-format -msgid "Active (%d)" -msgstr "" - -#. translators: %d: pending subscriber count -#: includes/class-opentrust-admin.php:794 -#, php-format -msgid "Pending (%d)" -msgstr "" - -#: includes/class-opentrust-admin.php:797 -msgid "Export CSV" -msgstr "" - -#: includes/class-opentrust-admin.php:808 -#: includes/class-opentrust-cpt.php:314 -#: includes/class-opentrust-cpt.php:805 -#, fuzzy -msgid "Status" -msgstr "Status" - -#: includes/class-opentrust-admin.php:809 -msgid "Categories" -msgstr "" - -#: includes/class-opentrust-admin.php:810 -msgid "Subscribed" -msgstr "" - -#: includes/class-opentrust-admin.php:811 -#: includes/class-opentrust-version.php:163 -#: templates/partials/policies.php:40 -#, fuzzy -msgid "Actions" -msgstr "Acties" - -#: includes/class-opentrust-admin.php:816 -msgid "No subscribers yet." -msgstr "" - -#: includes/class-opentrust-admin.php:851 -msgid "Mark this subscriber as verified? No confirmation email will be sent." -msgstr "" - -#: includes/class-opentrust-admin.php:852 -msgid "Verify" -msgstr "" - -#: includes/class-opentrust-admin.php:858 -msgid "Delete this subscriber?" -msgstr "" - -#: includes/class-opentrust-admin.php:859 -msgid "Delete" -msgstr "" - -#: includes/class-opentrust-admin.php:950 -msgid "No file was uploaded." -msgstr "" - -#: includes/class-opentrust-admin.php:956 -msgid "File upload failed. Please try again." -msgstr "" - -#: includes/class-opentrust-admin.php:962 -msgid "Invalid upload." -msgstr "" - -#: includes/class-opentrust-admin.php:968 -msgid "File must be between 1 byte and 2 MB." -msgstr "" - -#: includes/class-opentrust-admin.php:978 -msgid "File must be a .csv file." -msgstr "" - -#: includes/class-opentrust-admin.php:986 -msgid "File appears to be binary, not a CSV." -msgstr "" - -#: includes/class-opentrust-admin.php:1031 -msgid "Heads up: citation fidelity is not guaranteed on your active provider." -msgstr "" - -#. translators: %s: provider label, e.g. OpenAI -#: includes/class-opentrust-admin.php:1036 -#, php-format -msgid "You are currently using %s. Only Anthropic uses a structural Citations API — every other provider relies on prompted citation tags the model can ignore or fabricate. For a published trust center, switch to Anthropic below." -msgstr "" - -#: includes/class-opentrust-admin.php:1047 -msgid "OpenTrust uses Anthropic Claude with the native Citations API to answer visitor questions about your trust center. Every claim the assistant makes is tied to an exact quote from one of your published documents — so no policy text is invented and nothing is paraphrased into something you did not actually publish." -msgstr "" - -#: includes/class-opentrust-admin.php:1054 -msgid "Why Anthropic, and not OpenAI or any other provider?" -msgstr "" - -#: includes/class-opentrust-admin.php:1059 -msgid "A trust center is a compliance surface. If the assistant invents a security commitment you never made, that is not a UX papercut — it is a misrepresentation of your security posture, and your customers and auditors will hold you to it." -msgstr "" - -#: includes/class-opentrust-admin.php:1067 -msgid "Anthropic is the only major provider that exposes a structural Citations API. Documents are sent as typed blocks and the model emits citations as first-class events containing the exact source document and the exact quoted text. The model literally cannot return a citation for text that is not in your source documents." -msgstr "" - -#: includes/class-opentrust-admin.php:1073 -msgid "Every other provider (including OpenAI and any model accessed via OpenRouter) relies on prompted citation tags that we parse out of the answer after the fact. That works most of the time, but the model can ignore the instructions, make up document IDs, or attach a citation to a sentence it actually hallucinated. We support these providers as an escape hatch for organizations that genuinely cannot use Anthropic for procurement or data-residency reasons — but we very, very strongly recommend you do not run a public trust center on them." -msgstr "" - -#: includes/class-opentrust-admin.php:1104 -msgid "Choose a provider and add your key" -msgstr "" - -#: includes/class-opentrust-admin.php:1116 -msgid "Step 1 — Connect Anthropic" -msgstr "" - -#: includes/class-opentrust-admin.php:1122 -msgid "Advanced: use a different provider (not recommended)" -msgstr "" - -#: includes/class-opentrust-admin.php:1125 -msgid "These providers cannot guarantee citation fidelity." -msgstr "" - -#: includes/class-opentrust-admin.php:1127 -msgid "OpenAI and OpenRouter rely on prompted [[cite:document-id]] tags that we parse out of the answer after generation. The model can ignore the instruction, invent document IDs, or attach a citation to a sentence it actually hallucinated. We cannot detect when this happens." -msgstr "" - -#: includes/class-opentrust-admin.php:1130 -msgid "Do not use these providers for a published trust center" -msgstr "" - -#: includes/class-opentrust-admin.php:1131 -msgid "unless your organization genuinely cannot use Anthropic for procurement, contractual, or data-residency reasons. Inaccurate claims about your security posture are a real compliance risk." -msgstr "" - -#: includes/class-opentrust-admin.php:1170 -msgid "Required for citation fidelity" -msgstr "" - -#: includes/class-opentrust-admin.php:1176 -msgid "Uses Claude with the native Citations API. Every quote the assistant attributes to one of your documents is structurally guaranteed to come from that document." -msgstr "" - -#. translators: %s: provider name (e.g. Anthropic) -#: includes/class-opentrust-admin.php:1184 -#, php-format -msgid "Get a %s API key" -msgstr "" - -#: includes/class-opentrust-admin.php:1197 -msgid "Remove the saved key for this provider?" -msgstr "" - -#: includes/class-opentrust-admin.php:1198 -msgid "Replace key" -msgstr "" - -#. translators: %s: provider name (e.g. Anthropic) -#: includes/class-opentrust-admin.php:1208 -#, php-format -msgid "Paste your %s API key…" -msgstr "" - -#: includes/class-opentrust-admin.php:1212 -msgid "Validate & save" -msgstr "" - -#: includes/class-opentrust-admin.php:1229 -msgid "Step 2 — Pick a model and tune defaults" -msgstr "" - -#: includes/class-opentrust-admin.php:1251 -msgid "Active model" -msgstr "" - -#: includes/class-opentrust-admin.php:1255 -msgid "No cached models found. Use Refresh to re-fetch the model list." -msgstr "" - -#: includes/class-opentrust-admin.php:1263 -msgid "Recommended" -msgstr "" - -#: includes/class-opentrust-admin.php:1270 -msgid "Refresh models" -msgstr "" - -#. translators: %s: human-readable time difference (e.g. "5 minutes") -#: includes/class-opentrust-admin.php:1280 -#, php-format -msgid "Model list cached %s ago." -msgstr "" - -#: includes/class-opentrust-admin.php:1288 -msgid "Daily token budget" -msgstr "" - -#: includes/class-opentrust-admin.php:1291 -msgid "Hard cap per site per day. Default 500,000 tokens (~$12/day at Sonnet 4.5 rates)." -msgstr "" - -#: includes/class-opentrust-admin.php:1295 -msgid "Monthly token budget" -msgstr "" - -#: includes/class-opentrust-admin.php:1298 -msgid "Hard cap per site per month. Default 10,000,000 tokens." -msgstr "" - -#: includes/class-opentrust-admin.php:1302 -msgid "Rate limit — per IP" -msgstr "" - -#: includes/class-opentrust-admin.php:1304 -msgid "messages per minute" -msgstr "" - -#: includes/class-opentrust-admin.php:1308 -msgid "Rate limit — per session" -msgstr "" - -#: includes/class-opentrust-admin.php:1310 -msgid "messages per hour" -msgstr "" - -#: includes/class-opentrust-admin.php:1314 -msgid "Max message length" -msgstr "" - -#: includes/class-opentrust-admin.php:1316 -msgid "characters" -msgstr "" - -#: includes/class-opentrust-admin.php:1321 -msgid "Refuse-to-answer contact URL" -msgstr "" - -#: includes/class-opentrust-admin.php:1324 -msgid "When the AI cannot confidently answer a question, it links here. Leave blank to use the trust center home." -msgstr "" - -#: includes/class-opentrust-admin.php:1329 -msgid "Visitor display" -msgstr "" - -#: includes/class-opentrust-admin.php:1333 -msgid "Show \"Powered by {model}\" under the chat input" -msgstr "" - -#: includes/class-opentrust-admin.php:1339 -msgid "Analytics logging" -msgstr "" - -#: includes/class-opentrust-admin.php:1343 -msgid "Log anonymized visitor questions for admin review (90-day auto-purge, no PII)" -msgstr "" - -#: includes/class-opentrust-admin.php:1349 -msgid "Advanced — Turnstile anti-abuse" -msgstr "" - -#: includes/class-opentrust-admin.php:1351 -msgid "Cloudflare Turnstile is optional but recommended for public sites. It challenges suspicious visitors on the first message of each session. You need a free Cloudflare account to get site/secret keys." -msgstr "" - -#: includes/class-opentrust-admin.php:1355 -msgid "Enable Turnstile for chat" -msgstr "" - -#: includes/class-opentrust-admin.php:1359 -msgid "Require Turnstile verification on first chat message" -msgstr "" - -#: includes/class-opentrust-admin.php:1361 -msgid "Reuses the Turnstile site/secret keys you configure in the General tab." -msgstr "" - -#: includes/class-opentrust-admin.php:1366 -msgid "Save AI settings" -msgstr "" - -#: includes/class-opentrust-admin.php:1413 -#: includes/class-opentrust-admin.php:1478 -#: includes/class-opentrust-admin.php:1515 -#: includes/class-opentrust-admin.php:1750 -#: includes/class-opentrust-admin.php:1791 -#: includes/class-opentrust-admin.php:1808 -msgid "You do not have permission to perform this action." -msgstr "" - -#: includes/class-opentrust-admin.php:1422 -#: includes/class-opentrust-admin.php:1486 -#: includes/class-opentrust-admin.php:1522 -msgid "Unknown provider." -msgstr "" - -#: includes/class-opentrust-admin.php:1426 -msgid "API key cannot be empty." -msgstr "" - -#: includes/class-opentrust-admin.php:1433 -msgid "Validation failed." -msgstr "" - -#. translators: 1: provider label, 2: provider error message -#: includes/class-opentrust-admin.php:1435 -#, php-format -msgid "%1$s rejected the key: %2$s" -msgstr "" - -#. translators: 1: provider label, 2: number of models -#: includes/class-opentrust-admin.php:1471 -#, php-format -msgid "%1$s key validated. Found %2$d model(s)." -msgstr "" - -#: includes/class-opentrust-admin.php:1509 -msgid "Key removed." -msgstr "" - -#: includes/class-opentrust-admin.php:1528 -msgid "No key on file for this provider." -msgstr "" - -#: includes/class-opentrust-admin.php:1534 -msgid "Refresh failed." -msgstr "" - -#. translators: %s: error message from the provider -#: includes/class-opentrust-admin.php:1536 -#, php-format -msgid "Refresh failed: %s" -msgstr "" - -#. translators: %d: number of models -#: includes/class-opentrust-admin.php:1552 -#, php-format -msgid "Model list refreshed. Found %d model(s)." -msgstr "" - -#: includes/class-opentrust-admin.php:1618 -msgid "AI Questions" -msgstr "" - -#: includes/class-opentrust-admin.php:1621 -msgid "Questions visitors have asked your trust center chat. Identifiers are hashed and rows auto-purge after 90 days." -msgstr "" - -#: includes/class-opentrust-admin.php:1627 -msgid "Logging is ON" -msgstr "" - -#: includes/class-opentrust-admin.php:1629 -msgid "Logging is OFF" -msgstr "" - -#. translators: %d: number of questions -#: includes/class-opentrust-admin.php:1635 -#, php-format -msgid "%d question logged in the last 90 days" -msgid_plural "%d questions logged in the last 90 days" -msgstr[0] "" -msgstr[1] "" - -#: includes/class-opentrust-admin.php:1639 -msgid "Toggle visitor question logging?" -msgstr "" - -#: includes/class-opentrust-admin.php:1640 -msgid "Disable logging" -msgstr "" - -#: includes/class-opentrust-admin.php:1640 -msgid "Enable logging" -msgstr "" - -#: includes/class-opentrust-admin.php:1648 -#, fuzzy -msgid "Search" -msgstr "Zoeken" - -#: includes/class-opentrust-admin.php:1649 -msgid "Search questions…" -msgstr "" - -#: includes/class-opentrust-admin.php:1652 -#: includes/class-opentrust-admin.php:1679 -msgid "Model" -msgstr "" - -#: includes/class-opentrust-admin.php:1654 -msgid "Any" -msgstr "" - -#: includes/class-opentrust-admin.php:1661 -msgid "From" -msgstr "" - -#: includes/class-opentrust-admin.php:1665 -msgid "To" -msgstr "" - -#: includes/class-opentrust-admin.php:1668 -msgid "Filter" -msgstr "" - -#: includes/class-opentrust-admin.php:1669 -msgid "Reset" -msgstr "" - -#: includes/class-opentrust-admin.php:1670 -msgid "Download CSV" -msgstr "" - -#: includes/class-opentrust-admin.php:1677 -#: includes/class-opentrust-version.php:162 -msgid "Date" -msgstr "" - -#: includes/class-opentrust-admin.php:1678 -msgid "Question" -msgstr "" - -#: includes/class-opentrust-admin.php:1680 -msgid "Cites" -msgstr "" - -#: includes/class-opentrust-admin.php:1681 -msgid "Tokens" -msgstr "" - -#: includes/class-opentrust-admin.php:1682 -msgid "Latency" -msgstr "" - -#: includes/class-opentrust-admin.php:1687 -msgid "No questions logged yet." -msgstr "" - -#: includes/class-opentrust-admin.php:1696 -msgid "REFUSED" -msgstr "" - -#: includes/class-opentrust-admin.php:1736 -msgid "Danger zone" -msgstr "" - -#: includes/class-opentrust-admin.php:1737 -msgid "Permanently delete all logged questions? This cannot be undone." -msgstr "" - -#: includes/class-opentrust-admin.php:1738 -msgid "Clear entire question log" -msgstr "" - -#: includes/class-opentrust-admin.php:1799 -msgid "Question log cleared." -msgstr "" - -#: includes/class-opentrust-admin.php:1818 -msgid "Logging enabled." -msgstr "" - -#: includes/class-opentrust-admin.php:1818 -msgid "Logging disabled." -msgstr "" - -#: includes/class-opentrust-admin.php:1866 -msgid "Select Badge Image" -msgstr "" - -#: includes/class-opentrust-admin.php:1867 -msgid "Use as Badge" -msgstr "" - -#: includes/class-opentrust-admin.php:1882 -msgid "No match in catalog, just keep typing to add manually." -msgstr "" - -#: includes/class-opentrust-admin.php:1883 -msgid "Auto-filled from catalog, you may want to verify this." -msgstr "" - -#: includes/class-opentrust-admin.php:1884 -msgid "Auto-filled template, please verify this matches how you use this service." -msgstr "" - -#: includes/class-opentrust-admin.php:1885 -msgid "click to autofill" -msgstr "" - -#: includes/class-opentrust-admin.php:1886 -msgid "Catalog suggestions" -msgstr "" - -#: includes/class-opentrust-admin.php:1945 -msgid "Every policy broadcast sent from the plugin is logged here. One row per broadcast event." -msgstr "" - -#: includes/class-opentrust-admin.php:1949 -msgid "No broadcasts yet. When you save a policy with \"Broadcast this change to subscribers\" ticked, the send will be logged here." -msgstr "" - -#: includes/class-opentrust-admin.php:1954 -#: includes/class-opentrust-cpt.php:66 -#: templates/partials/policies.php:36 -#, fuzzy -msgid "Policy" -msgstr "Beleid" - -#: includes/class-opentrust-admin.php:1955 -msgid "Sent at" -msgstr "" - -#: includes/class-opentrust-admin.php:1956 -msgid "Delivered" -msgstr "" - -#: includes/class-opentrust-admin.php:1957 -msgid "Failed" -msgstr "" - -#: includes/class-opentrust-admin.php:1972 -msgid "(deleted policy)" -msgstr "" - -#: includes/class-opentrust-admin.php:2042 -msgid "OpenTrust requires pretty permalinks." -msgstr "" - -#. translators: %s: link to Settings → Permalinks -#: includes/class-opentrust-admin.php:2046 -#, php-format -msgid "Your site is using \"Plain\" permalinks. Please go to %s and choose any other option (Post name is the WordPress default)." -msgstr "" - -#: includes/class-opentrust-admin.php:2047 -msgid "Settings → Permalinks" -msgstr "" - -#: includes/class-opentrust-admin.php:2052 -msgid "Without pretty permalinks, every link OpenTrust generates returns 404 — including the trust center page itself, the subscribe form, and every confirmation, unsubscribe, and broadcast email link sent to subscribers. Visitors will not be able to subscribe, confirm, or unsubscribe." -msgstr "" - -#: includes/class-opentrust-admin.php:2056 -msgid "Read-only fallback if you cannot change permalinks" -msgstr "" - -#: includes/class-opentrust-admin.php:2060 -msgid "You can preview the trust center via raw query-string URLs, but no email links will work and visitors cannot subscribe:" -msgstr "" - -#: includes/class-opentrust-admin.php:2068 -msgid "This is for testing only." -msgstr "" - -#: includes/class-opentrust-admin.php:2069 -msgid "Switching to pretty permalinks is the only supported configuration." -msgstr "" - -#: includes/class-opentrust-chat.php:90 -#, fuzzy -msgid "Invalid nonce — refresh the page and try again." -msgstr "Ongeldige nonce — ververs de pagina en probeer opnieuw." - -#: includes/class-opentrust-chat.php:113 -#, fuzzy -msgid "Please complete the anti-abuse challenge and try again." -msgstr "Voltooi de anti-misbruikcontrole en probeer opnieuw." - -#: includes/class-opentrust-chat.php:125 -msgid "You are sending messages too fast. Please wait a moment and try again." -msgstr "" - -#: includes/class-opentrust-chat.php:136 -msgid "You have reached the per-session message limit. Please wait a bit and try again." -msgstr "" - -#: includes/class-opentrust-chat.php:156 -msgid "AI chat is not configured on this site." -msgstr "" - -#: includes/class-opentrust-chat.php:165 -msgid "Configured provider is unknown." -msgstr "" - -#: includes/class-opentrust-chat.php:174 -msgid "No API key stored for the configured provider." -msgstr "" - -#: includes/class-opentrust-chat.php:187 -msgid "Your message is empty." -msgstr "" - -#: includes/class-opentrust-chat.php:197 -msgid "Published content exceeds the AI chat size limit." -msgstr "" - -#: includes/class-opentrust-chat.php:207 -msgid "The daily chat budget for this site has been reached. Please try again later." -msgstr "" - -#: includes/class-opentrust-chat.php:389 -msgid "Chat provider failed unexpectedly." -msgstr "" - -#: includes/class-opentrust-cpt.php:46 -msgid "Pick from the catalog or type your own, e.g. Datadog, Stripe, or AWS" -msgstr "" - -#: includes/class-opentrust-cpt.php:49 -msgid "Pick from the catalog or type your own, e.g. Analytics or Transactional Email" -msgstr "" - -#: includes/class-opentrust-cpt.php:52 -msgid "Pick from the catalog or type your own, e.g. SOC 2 Type II or ISO 27001" -msgstr "" - -#: includes/class-opentrust-cpt.php:67 -msgid "Add Policy" -msgstr "" - -#: includes/class-opentrust-cpt.php:68 -msgid "Add New Policy" -msgstr "" - -#: includes/class-opentrust-cpt.php:69 -msgid "Edit Policy" -msgstr "" - -#: includes/class-opentrust-cpt.php:70 -msgid "New Policy" -msgstr "" - -#: includes/class-opentrust-cpt.php:71 -#, fuzzy -msgid "View Policy" -msgstr "Beleid bekijken" - -#: includes/class-opentrust-cpt.php:72 -msgid "Search Policies" -msgstr "" - -#: includes/class-opentrust-cpt.php:73 -msgid "No policies found." -msgstr "" - -#: includes/class-opentrust-cpt.php:74 -msgid "No policies in trash." -msgstr "" - -#: includes/class-opentrust-cpt.php:99 -#: includes/class-opentrust-cpt.php:108 -#: templates/chat.php:45 -#: templates/partials/hero.php:49 -#: templates/trust-center.php:107 -#, fuzzy -msgid "Certifications" -msgstr "Certificeringen" - -#: includes/class-opentrust-cpt.php:100 -msgid "Certification" -msgstr "" - -#: includes/class-opentrust-cpt.php:101 -msgid "Add Certification" -msgstr "" - -#: includes/class-opentrust-cpt.php:102 -msgid "Add New Certification" -msgstr "" - -#: includes/class-opentrust-cpt.php:103 -msgid "Edit Certification" -msgstr "" - -#: includes/class-opentrust-cpt.php:104 -msgid "New Certification" -msgstr "" - -#: includes/class-opentrust-cpt.php:105 -msgid "Search Certifications" -msgstr "" - -#: includes/class-opentrust-cpt.php:106 -msgid "No certifications found." -msgstr "" - -#: includes/class-opentrust-cpt.php:107 -msgid "No certifications in trash." -msgstr "" - -#: includes/class-opentrust-cpt.php:133 -msgid "Subprocessor" -msgstr "" - -#: includes/class-opentrust-cpt.php:134 -msgid "Add Subprocessor" -msgstr "" - -#: includes/class-opentrust-cpt.php:135 -msgid "Add New Subprocessor" -msgstr "" - -#: includes/class-opentrust-cpt.php:136 -msgid "Edit Subprocessor" -msgstr "" - -#: includes/class-opentrust-cpt.php:137 -msgid "New Subprocessor" -msgstr "" - -#: includes/class-opentrust-cpt.php:138 -msgid "Search Subprocessors" -msgstr "" - -#: includes/class-opentrust-cpt.php:139 -msgid "No subprocessors found." -msgstr "" - -#: includes/class-opentrust-cpt.php:140 -msgid "No subprocessors in trash." -msgstr "" - -#: includes/class-opentrust-cpt.php:166 -msgid "Data Practice" -msgstr "" - -#: includes/class-opentrust-cpt.php:167 -msgid "Add Data Practice" -msgstr "" - -#: includes/class-opentrust-cpt.php:168 -msgid "Add New Data Practice" -msgstr "" - -#: includes/class-opentrust-cpt.php:169 -msgid "Edit Data Practice" -msgstr "" - -#: includes/class-opentrust-cpt.php:170 -msgid "New Data Practice" -msgstr "" - -#: includes/class-opentrust-cpt.php:171 -msgid "Search Data Practices" -msgstr "" - -#: includes/class-opentrust-cpt.php:172 -msgid "No data practices found." -msgstr "" - -#: includes/class-opentrust-cpt.php:173 -msgid "No data practices in trash." -msgstr "" - -#: includes/class-opentrust-cpt.php:202 -msgid "Certification Details" -msgstr "" - -#: includes/class-opentrust-cpt.php:207 -msgid "Email subscribers" -msgstr "" - -#: includes/class-opentrust-cpt.php:210 -msgid "Policy Details" -msgstr "" - -#: includes/class-opentrust-cpt.php:211 -msgid "Subprocessor Details" -msgstr "" - -#: includes/class-opentrust-cpt.php:212 -msgid "Data Practice Details" -msgstr "" - -#: includes/class-opentrust-cpt.php:231 -msgid "Broadcast triggered, but no active subscribers are opted in to policy updates." -msgstr "" - -#. translators: %d: subscriber count -#: includes/class-opentrust-cpt.php:235 -#, php-format -msgid "Broadcast just sent to %d subscriber." -msgid_plural "Broadcast just sent to %d subscribers." -msgstr[0] "" -msgstr[1] "" - -#. translators: 1: delivered count, 2: failed count -#: includes/class-opentrust-cpt.php:239 -#, php-format -msgid "Broadcast finished: %1$d delivered, %2$d failed." -msgstr "" - -#: includes/class-opentrust-cpt.php:251 -msgid "Broadcast this change to subscribers" -msgstr "" - -#: includes/class-opentrust-cpt.php:253 -msgid "Emails all active subscribers who opted in to policy updates. The checkbox resets after each save." -msgstr "" - -#. translators: %s: date and time -#: includes/class-opentrust-cpt.php:261 -#, php-format -msgid "Last broadcast: %s" -msgstr "" - -#. translators: 1: delivered count, 2: failed count -#: includes/class-opentrust-cpt.php:266 -#, php-format -msgid "%1$d delivered, %2$d failed" -msgstr "" - -#: includes/class-opentrust-cpt.php:288 -msgid "Certified (audited by a third party)" -msgstr "" - -#: includes/class-opentrust-cpt.php:289 -msgid "Compliant (self-attested adherence)" -msgstr "" - -#: includes/class-opentrust-cpt.php:293 -#: includes/class-opentrust-render.php:829 -#, fuzzy -msgid "Active" -msgstr "Actief" - -#: includes/class-opentrust-cpt.php:294 -#: includes/class-opentrust-render.php:830 -#, fuzzy -msgid "In Progress" -msgstr "In aanvraag" - -#: includes/class-opentrust-cpt.php:295 -#: includes/class-opentrust-render.php:831 -#, fuzzy -msgid "Expired" -msgstr "Verlopen" - -#: includes/class-opentrust-cpt.php:299 -msgid "Certification Type" -msgstr "" - -#: includes/class-opentrust-cpt.php:305 -msgid "Certified means a third-party auditor issued a certificate with dates. Compliant means you self-attest adherence to the standard without a formal audit." -msgstr "" - -#: includes/class-opentrust-cpt.php:309 -#: includes/class-opentrust-cpt.php:804 -#, fuzzy -msgid "Issuing Body" -msgstr "Uitgegeven door" - -#: includes/class-opentrust-cpt.php:310 -msgid "e.g., AICPA, ISO/IEC, PCI Security Standards Council" -msgstr "" - -#: includes/class-opentrust-cpt.php:323 -msgid "Issue Date" -msgstr "" - -#: includes/class-opentrust-cpt.php:328 -#: includes/class-opentrust-cpt.php:806 -#, fuzzy -msgid "Expiry Date" -msgstr "Vervaldatum" - -#: includes/class-opentrust-cpt.php:333 -msgid "Badge Image" -msgstr "" - -#: includes/class-opentrust-cpt.php:336 -msgid "Select Badge" -msgstr "" - -#: includes/class-opentrust-cpt.php:341 -msgid "Description" -msgstr "" - -#: includes/class-opentrust-cpt.php:343 -msgid "Brief description of this certification and its scope." -msgstr "" - -#. translators: %s: policy version number -#: includes/class-opentrust-cpt.php:371 -#: templates/partials/policy-single.php:97 -#, fuzzy -#, php-format -msgid "Version %s" -msgstr "Versie %s" - -#: includes/class-opentrust-cpt.php:374 -msgid "Regular saves update the current version. Use the checkbox below to formally publish a new version." -msgstr "" - -#: includes/class-opentrust-cpt.php:383 -msgid "Publish as new version" -msgstr "" - -#. translators: %1$d: current version number, %2$d: next version number -#: includes/class-opentrust-cpt.php:388 -#, php-format -msgid "This will save the current content as v%1$d and create v%2$d. Only check this for formal, published changes — not minor edits." -msgstr "" - -#: includes/class-opentrust-cpt.php:397 -msgid "What changed?" -msgstr "" - -#: includes/class-opentrust-cpt.php:400 -msgid "e.g., Updated data retention from 90 to 60 days" -msgstr "" - -#: includes/class-opentrust-cpt.php:401 -msgid "Shown in the public version history." -msgstr "" - -#: includes/class-opentrust-cpt.php:408 -#: includes/class-opentrust-cpt.php:835 -#: templates/partials/policies.php:37 -#, fuzzy -msgid "Category" -msgstr "Categorie" - -#: includes/class-opentrust-cpt.php:417 -msgid "Effective Date" -msgstr "" - -#: includes/class-opentrust-cpt.php:422 -msgid "Next Review Date" -msgstr "" - -#: includes/class-opentrust-cpt.php:427 -#: includes/class-opentrust-cpt.php:556 -msgid "Sort Order" -msgstr "" - -#: includes/class-opentrust-cpt.php:429 -#: includes/class-opentrust-cpt.php:558 -msgid "Lower numbers appear first." -msgstr "" - -#: includes/class-opentrust-cpt.php:435 -msgid "Allow PDF download" -msgstr "" - -#: includes/class-opentrust-cpt.php:453 -#: includes/class-opentrust-cpt.php:518 -#: includes/class-opentrust-cpt.php:854 -#: templates/partials/data-practices.php:96 -#: templates/partials/subprocessors.php:37 -#, fuzzy -msgid "Purpose" -msgstr "Doel" - -#: includes/class-opentrust-cpt.php:455 -msgid "What does this subprocessor do for your company?" -msgstr "" - -#: includes/class-opentrust-cpt.php:459 -#: templates/partials/subprocessors.php:38 -#, fuzzy -msgid "Data Processed" -msgstr "Verwerkte gegevens" - -#: includes/class-opentrust-cpt.php:461 -msgid "What types of data does this subprocessor handle?" -msgstr "" - -#: includes/class-opentrust-cpt.php:465 -msgid "Country / Location" -msgstr "" - -#: includes/class-opentrust-cpt.php:466 -msgid "e.g., United States" -msgstr "" - -#: includes/class-opentrust-cpt.php:470 -#: templates/partials/subprocessors.php:41 -#, fuzzy -msgid "Website" -msgstr "Website" - -#: includes/class-opentrust-cpt.php:477 -#, fuzzy -msgid "DPA Signed" -msgstr "DPA ondertekend" - -#: includes/class-opentrust-cpt.php:479 -msgid "A Data Processing Agreement (DPA) is a contract between you and the subprocessor covering how they handle personal data on your behalf. Check this box once your organization has signed one with this vendor." -msgstr "" - -#: includes/class-opentrust-cpt.php:503 -msgid "Data Items Collected" -msgstr "" - -#: includes/class-opentrust-cpt.php:512 -#: includes/class-opentrust-cpt.php:550 -msgid "Type and press Enter..." -msgstr "" - -#: includes/class-opentrust-cpt.php:525 -#: templates/partials/data-practices.php:103 -#, fuzzy -msgid "Legal Basis" -msgstr "Wettelijke grondslag" - -#: includes/class-opentrust-cpt.php:527 -msgid "— Select —" -msgstr "" - -#: includes/class-opentrust-cpt.php:534 -msgid "Retention Period" -msgstr "" - -#: includes/class-opentrust-cpt.php:535 -msgid "e.g., 30 days" -msgstr "" - -#: includes/class-opentrust-cpt.php:541 -#: templates/partials/data-practices.php:117 -#, fuzzy -msgid "Shared With" -msgstr "Gedeeld met" - -#: includes/class-opentrust-cpt.php:653 -msgid "Broadcast triggered, but no active subscribers are opted in to policy updates. Nothing was sent." -msgstr "" - -#. translators: %d: subscriber count -#: includes/class-opentrust-cpt.php:657 -#, php-format -msgid "Broadcast sent to %d subscriber." -msgid_plural "Broadcast sent to %d subscribers." -msgstr[0] "" -msgstr[1] "" - -#. translators: 1: delivered count, 2: failed count -#: includes/class-opentrust-cpt.php:661 -#, php-format -msgid "Broadcast finished: %1$d delivered, %2$d failed. Check your SMTP configuration." -msgstr "" - -#: includes/class-opentrust-cpt.php:836 -#: includes/class-opentrust-version.php:161 -#: templates/partials/policies.php:38 -#, fuzzy -msgid "Version" -msgstr "Versie" - -#: includes/class-opentrust-cpt.php:855 -#: templates/partials/subprocessors.php:39 -#, fuzzy -msgid "Location" -msgstr "Locatie" - -#: includes/class-opentrust-cpt.php:856 -#: templates/partials/subprocessors.php:40 -#, fuzzy -msgid "DPA" -msgstr "DPA" - -#: includes/class-opentrust-cpt.php:875 -#, fuzzy -msgid "Data Items" -msgstr "Gegevensitems" - -#: includes/class-opentrust-cpt.php:876 -msgid "Order" -msgstr "" - -#: includes/class-opentrust-notify.php:20 -msgid "Policy Updates" -msgstr "" - -#: includes/class-opentrust-notify.php:21 -msgid "Certification Updates" -msgstr "" - -#: includes/class-opentrust-notify.php:22 -msgid "Subprocessor Changes" -msgstr "" - -#: includes/class-opentrust-notify.php:23 -msgid "Data Practice Changes" -msgstr "" - -#: includes/class-opentrust-notify.php:185 -#, fuzzy -msgid "Please enter a valid email address." -msgstr "Voer een geldig e-mailadres in." - -#: includes/class-opentrust-notify.php:192 -msgid "This email is already subscribed." -msgstr "" - -#: includes/class-opentrust-notify.php:239 -msgid "Something went wrong. Please try again later." -msgstr "" - -#: includes/class-opentrust-notify.php:247 -#, fuzzy -msgid "Please check your inbox and click the confirmation link." -msgstr "Controleer je inbox en klik op de bevestigingslink." - -#: includes/class-opentrust-notify.php:456 -msgid "Could not read the uploaded file." -msgstr "" - -#: includes/class-opentrust-notify.php:463 -msgid "Could not open the uploaded file." -msgstr "" - -#. translators: %d: row cap -#: includes/class-opentrust-notify.php:488 -#, php-format -msgid "Import stopped at row %d (maximum row cap reached)." -msgstr "" - -#: includes/class-opentrust-notify.php:509 -msgid "CSV is missing a required \"email\" column." -msgstr "" - -#. translators: 1: row number -#: includes/class-opentrust-notify.php:527 -#, php-format -msgid "Row %d: invalid or missing email." -msgstr "" - -#. translators: 1: row number, 2: email -#: includes/class-opentrust-notify.php:536 -#, php-format -msgid "Row %1$d: duplicate email %2$s in CSV — skipped." -msgstr "" - -#. translators: 1: row number, 2: email -#: includes/class-opentrust-notify.php:618 -#, php-format -msgid "Row %1$d: failed to update %2$s." -msgstr "" - -#. translators: 1: row number, 2: email -#: includes/class-opentrust-notify.php:642 -#, php-format -msgid "Row %1$d: failed to insert %2$s." -msgstr "" - -#. translators: %s: subscriber name -#: includes/class-opentrust-notify.php:896 -#: includes/class-opentrust-notify.php:951 -#, fuzzy -#, php-format -msgid "Hi %s," -msgstr "Hoi %s," - -#: includes/class-opentrust-notify.php:897 -#: includes/class-opentrust-notify.php:952 -msgid "Hi," -msgstr "" - -#. translators: 1: company name, 2: policy title -#: includes/class-opentrust-notify.php:905 -#, fuzzy -#, php-format -msgid "[%1$s] Policy updated: %2$s" -msgstr "[%1$s] Beleid bijgewerkt: %2$s" - -#. translators: %s: company name -#: includes/class-opentrust-notify.php:945 -#, fuzzy -#, php-format -msgid "Confirm your subscription to %s Trust Center updates" -msgstr "Bevestig je aanmelding voor Trust Center-updates van %s" - -#: includes/class-opentrust-notify.php:1090 -#: includes/class-opentrust-notify.php:1247 -#, fuzzy -msgid "Invalid request." -msgstr "Ongeldig verzoek." - -#: includes/class-opentrust-notify.php:1150 -msgid "Too many attempts. Please try again later." -msgstr "" - -#: includes/class-opentrust-notify.php:1212 -#, fuzzy -msgid "Please complete the security check." -msgstr "Voltooi de beveiligingscontrole." - -#: includes/class-opentrust-notify.php:1235 -msgid "Security verification failed. Please try again." -msgstr "" - -#: includes/class-opentrust-notify.php:1262 -#, fuzzy -msgid "Please select at least one category." -msgstr "Selecteer ten minste één categorie." - -#: includes/class-opentrust-notify.php:1267 -msgid "Your preferences have been updated." -msgstr "" - -#: includes/class-opentrust-notify.php:1268 -msgid "Could not update preferences. Please try again." -msgstr "" - -#: includes/class-opentrust-render.php:87 -msgid "Session expired. Please reload the page and try again." -msgstr "" - -#: includes/class-opentrust-render.php:93 -#, fuzzy -msgid "Please enter a question." -msgstr "Voer een vraag in." - -#: includes/class-opentrust-render.php:102 -msgid "AI chat is not configured." -msgstr "" - -#: includes/class-opentrust-render.php:107 -msgid "AI chat is temporarily unavailable." -msgstr "" - -#: includes/class-opentrust-render.php:420 -msgid "Page not found." -msgstr "" - -#: includes/class-opentrust-render.php:421 -#: templates/partials/policy-single.php:56 -#: templates/partials/subscribe.php:21 -#, fuzzy -msgid "Back to Trust Center" -msgstr "Terug naar Trust Center" - -#: includes/class-opentrust-render.php:750 -msgid "Updated just now" -msgstr "" - -#. translators: %d: number of minutes since last update -#: includes/class-opentrust-render.php:755 -#, fuzzy -#, php-format -msgid "Updated %d minute ago" -msgid_plural "Updated %d minutes ago" -msgstr[0] "%d minuut geleden bijgewerkt" -msgstr[1] "%d minuten geleden bijgewerkt" - -#. translators: %d: number of hours since last update -#: includes/class-opentrust-render.php:762 -#, fuzzy -#, php-format -msgid "Updated %d hour ago" -msgid_plural "Updated %d hours ago" -msgstr[0] "%d uur geleden bijgewerkt" -msgstr[1] "%d uur geleden bijgewerkt" - -#. translators: %d: number of days since last update -#: includes/class-opentrust-render.php:769 -#, fuzzy -#, php-format -msgid "Updated %d day ago" -msgid_plural "Updated %d days ago" -msgstr[0] "%d dag geleden bijgewerkt" -msgstr[1] "%d dagen geleden bijgewerkt" - -#. translators: %s = formatted date -#: includes/class-opentrust-render.php:775 -#, fuzzy -#, php-format -msgid "Updated %s" -msgstr "Bijgewerkt op %s" - -#: includes/class-opentrust-render.php:819 -msgid "Security" -msgstr "" - -#: includes/class-opentrust-render.php:820 -msgid "Privacy" -msgstr "" - -#: includes/class-opentrust-render.php:821 -msgid "Compliance" -msgstr "" - -#: includes/class-opentrust-render.php:822 -msgid "Operational" -msgstr "" - -#: includes/class-opentrust-render.php:837 -msgid "Consent" -msgstr "" - -#: includes/class-opentrust-render.php:838 -msgid "Contractual Necessity" -msgstr "" - -#: includes/class-opentrust-render.php:839 -msgid "Legitimate Interest" -msgstr "" - -#: includes/class-opentrust-render.php:840 -msgid "Legal Obligation" -msgstr "" - -#: includes/class-opentrust-render.php:841 -msgid "Vital Interest" -msgstr "" - -#: includes/class-opentrust-render.php:842 -msgid "Public Interest" -msgstr "" - -#: includes/class-opentrust-render.php:848 -msgid "Account Information" -msgstr "" - -#: includes/class-opentrust-render.php:849 -msgid "Contact Information" -msgstr "" - -#: includes/class-opentrust-render.php:850 -msgid "Personal Data" -msgstr "" - -#: includes/class-opentrust-render.php:851 -msgid "Financial Data" -msgstr "" - -#: includes/class-opentrust-render.php:852 -msgid "Usage & Analytics" -msgstr "" - -#: includes/class-opentrust-render.php:853 -msgid "Device & Technical" -msgstr "" - -#: includes/class-opentrust-render.php:854 -msgid "Behavioral Data" -msgstr "" - -#: includes/class-opentrust-render.php:855 -msgid "User Content" -msgstr "" - -#: includes/class-opentrust-render.php:856 -msgid "Communications" -msgstr "" - -#: includes/class-opentrust-render.php:857 -msgid "Location Data" -msgstr "" - -#: includes/class-opentrust-render.php:858 -msgid "Identity & Verification" -msgstr "" - -#: includes/class-opentrust-render.php:859 -msgid "Marketing & Preferences" -msgstr "" - -#: includes/class-opentrust-render.php:860 -msgid "Sensitive Data" -msgstr "" - -#: includes/class-opentrust-render.php:861 -msgid "Health Data" -msgstr "" - -#: includes/class-opentrust-version.php:128 -msgid "Version History" -msgstr "" - -#: includes/class-opentrust-version.php:150 -msgid "Current version:" -msgstr "" - -#: includes/class-opentrust-version.php:153 -msgid "Version history will appear after the first update." -msgstr "" - -#: includes/class-opentrust-version.php:170 -#: templates/partials/policy-single.php:158 -msgid "Current" -msgstr "" - -#: includes/class-opentrust-version.php:184 -#: includes/class-opentrust-version.php:185 -msgid "View" -msgstr "" - -#: includes/class-opentrust-version.php:188 -msgid "Compare" -msgstr "" - -#: includes/class-opentrust-version.php:189 -msgid "Diff" -msgstr "" - -#: includes/providers/class-opentrust-chat-provider-anthropic.php:37 -#: includes/providers/class-opentrust-chat-provider.php:45 -msgid "Anthropic" -msgstr "" - -#: includes/providers/class-opentrust-chat-provider-anthropic.php:51 -#: includes/providers/class-opentrust-chat-provider-openai.php:80 -msgid "API key is empty." -msgstr "" - -#: includes/providers/class-opentrust-chat-provider-anthropic.php:64 -#: includes/providers/class-opentrust-chat-provider-openai.php:90 -msgid "Request failed." -msgstr "" - -#: includes/providers/class-opentrust-chat-provider-anthropic.php:70 -msgid "No models available — your account may not be authorized." -msgstr "" - -#: includes/providers/class-opentrust-chat-provider-anthropic.php:133 -msgid "Anthropic adapter missing required args." -msgstr "" - -#: includes/providers/class-opentrust-chat-provider-anthropic.php:201 -msgid "Anthropic request failed." -msgstr "" - -#: includes/providers/class-opentrust-chat-provider-anthropic.php:258 -msgid "Tool call produced no content blocks." -msgstr "" - -#: includes/providers/class-opentrust-chat-provider-anthropic.php:286 -#: includes/providers/class-opentrust-chat-provider-openai.php:315 -msgid "Conversation exceeded tool-use depth limit." -msgstr "" - -#: includes/providers/class-opentrust-chat-provider-openai.php:66 -#: includes/providers/class-opentrust-chat-provider.php:51 -msgid "OpenAI" -msgstr "" - -#: includes/providers/class-opentrust-chat-provider-openai.php:96 -msgid "No chat models available for this key." -msgstr "" - -#: includes/providers/class-opentrust-chat-provider-openai.php:183 -msgid "OpenAI adapter missing required args." -msgstr "" - -#: includes/providers/class-opentrust-chat-provider-openai.php:259 -msgid "OpenAI request failed." -msgstr "" - -#: includes/providers/class-opentrust-chat-provider-openrouter.php:38 -#: includes/providers/class-opentrust-chat-provider.php:57 -msgid "OpenRouter" -msgstr "" - -#: includes/providers/class-opentrust-chat-provider.php:141 -#: includes/providers/class-opentrust-chat-provider.php:160 -#: includes/providers/class-opentrust-chat-provider.php:211 -msgid "Refused outbound request to disallowed host." -msgstr "" - -#. translators: %d: HTTP status code returned by the provider -#: includes/providers/class-opentrust-chat-provider.php:276 -#: includes/providers/class-opentrust-chat-provider.php:302 -#, php-format -msgid "Provider returned HTTP %d" -msgstr "" - -#. translators: %s: company name -#: templates/chat.php:56 -#, fuzzy -#, php-format -msgid "Ask %s — Trust Center" -msgstr "Vraag het aan %s — Trust Center" - -#: templates/chat.php:92 -#: templates/trust-center.php:100 -msgid "Skip to content" -msgstr "" - -#: templates/chat.php:94 -#: templates/partials/policy-single.php:36 -#: templates/trust-center.php:111 -msgid "Trust center navigation" -msgstr "" - -#: templates/chat.php:123 -msgid "Ask AI is not configured" -msgstr "" - -#: templates/chat.php:124 -msgid "The site administrator has not enabled the AI chat feature yet." -msgstr "" - -#: templates/chat.php:126 -msgid "Browse trust center" -msgstr "" - -#: templates/chat.php:154 -#: templates/chat.php:323 -#, fuzzy -msgid "You" -msgstr "Jij" - -#: templates/chat.php:156 -#: templates/chat.php:173 -#: templates/chat.php:324 -#, fuzzy -msgid "just now" -msgstr "zojuist" - -#: templates/chat.php:180 -#: templates/chat.php:316 -#, fuzzy -msgid "Sources" -msgstr "Bronnen" - -#: templates/chat.php:190 -#: templates/chat.php:326 -#, fuzzy -msgid "AI-generated answer. Not legal, security, or compliance advice. Verify against the sources above." -msgstr "Dit antwoord is door AI gegenereerd. Geen juridisch, beveiligings- of compliance-advies. Controleer het altijd aan de hand van de bronnen hierboven." - -#: templates/chat.php:200 -msgid "JavaScript is disabled — you can still ask one question below. The answer will load as a regular page." -msgstr "" - -#: templates/chat.php:203 -msgid "Your question" -msgstr "" - -#: templates/chat.php:210 -msgid "Ask" -msgstr "" - -#: templates/chat.php:221 -#, fuzzy -msgid "Are you SOC 2 compliant?" -msgstr "Zijn jullie SOC 2-compliant?" - -#: templates/chat.php:222 -#, fuzzy -msgid "Where is customer data stored?" -msgstr "Waar worden klantgegevens opgeslagen?" - -#: templates/chat.php:223 -msgid "What's your incident response process?" -msgstr "" - -#: templates/chat.php:224 -#, fuzzy -msgid "Which subprocessors do you use?" -msgstr "Welke subverwerkers gebruiken jullie?" - -#: templates/chat.php:236 -msgid "Suggested questions" -msgstr "" - -#: templates/chat.php:252 -msgid "Ask a question" -msgstr "" - -#: templates/chat.php:259 -#: templates/chat.php:303 -#, fuzzy -msgid "Ask anything about our security and compliance…" -msgstr "Stel een vraag over onze beveiliging en compliance…" - -#: templates/chat.php:261 -#: templates/chat.php:314 -#, fuzzy -msgid "Start a new conversation" -msgstr "Start een nieuw gesprek" - -#: templates/chat.php:264 -#: templates/chat.php:304 -#, fuzzy -msgid "Send" -msgstr "Versturen" - -#. translators: 1: link to trust center, 2: company name -#: templates/chat.php:275 -#, php-format -msgid "Grounded in the published %1$s for %2$s. AI-generated, not legal, security, or compliance advice. Always check the sources." -msgstr "" - -#: templates/chat.php:276 -msgid "trust center" -msgstr "" - -#: templates/chat.php:305 -#, fuzzy -msgid "Stop" -msgstr "Stoppen" - -#: templates/chat.php:306 -#, fuzzy -msgid "Thinking…" -msgstr "Denkt na…" - -#: templates/chat.php:307 -#, fuzzy -msgid "Connection lost. Retry?" -msgstr "Verbinding verbroken. Opnieuw proberen?" - -#: templates/chat.php:308 -#, fuzzy -msgid "Contact security team →" -msgstr "Neem contact op met het beveiligingsteam →" - -#: templates/chat.php:309 -#, fuzzy -msgid "Copy" -msgstr "Kopiëren" - -#: templates/chat.php:310 -#, fuzzy -msgid "Copied" -msgstr "Gekopieerd" - -#: templates/chat.php:311 -#, fuzzy -msgid "Share" -msgstr "Delen" - -#: templates/chat.php:312 -#: templates/partials/policy-single.php:123 -#, fuzzy -msgid "Print" -msgstr "Afdrukken" - -#: templates/chat.php:313 -#, fuzzy -msgid "Link copied" -msgstr "Link gekopieerd" - -#: templates/chat.php:315 -#, fuzzy -msgid "This conversation is getting long. Start fresh for better answers." -msgstr "Dit gesprek wordt lang — begin opnieuw voor de beste antwoorden." - -#: templates/chat.php:317 -#, fuzzy -msgid "I don't see enough information in our trust center to answer that confidently." -msgstr "In ons Trust Center staat niet genoeg informatie om die vraag met zekerheid te beantwoorden." - -#: templates/chat.php:318 -#, fuzzy -msgid "The AI provider returned an error. Please try again." -msgstr "De AI-provider gaf een fout. Probeer het opnieuw." - -#: templates/chat.php:319 -#, fuzzy -msgid "AI is temporarily unavailable. Please try again in a few minutes or browse our published content." -msgstr "De AI is tijdelijk niet beschikbaar. Probeer het over enkele minuten opnieuw of bekijk onze gepubliceerde content." - -#: templates/chat.php:320 -#, fuzzy -msgid "Message is too long." -msgstr "Het bericht is te lang." - -#: templates/chat.php:321 -#, fuzzy -msgid "Please wait a moment before asking again." -msgstr "Wacht even voordat je opnieuw een vraag stelt." - -#: templates/chat.php:322 -#, fuzzy -msgid "Cite source" -msgstr "Bron citeren" - -#: templates/chat.php:325 -#, fuzzy -msgid "No content returned by the model." -msgstr "Het model gaf geen antwoord terug." - -#. translators: %s: company name -#: templates/emails/confirmation.php:41 -#, fuzzy -#, php-format -msgid "Thank you for subscribing to trust center updates from %s. Please confirm your subscription by clicking the button below." -msgstr "Bedankt dat je je hebt aangemeld voor Trust Center-updates van %s. Bevestig je aanmelding door op de knop hieronder te klikken." - -#: templates/emails/confirmation.php:51 -msgid "Confirm subscription" -msgstr "" - -#: templates/emails/confirmation.php:57 -msgid "If the button above does not work, copy and paste this URL into your browser:" -msgstr "" - -#: templates/emails/confirmation.php:63 -msgid "If you did not request this subscription, you can safely ignore this email." -msgstr "" - -#. translators: 1: company name, 2: policy title -#: templates/emails/policy-broadcast.php:43 -#, fuzzy -#, php-format -msgid "%1$s has updated the following policy on our trust center:" -msgstr "%1$s heeft het volgende beleid bijgewerkt op het Trust Center:" - -#: templates/emails/policy-broadcast.php:55 -msgid "Effective date:" -msgstr "" - -#: templates/emails/policy-broadcast.php:65 -msgid "View the updated policy" -msgstr "" - -#: templates/emails/policy-broadcast.php:77 -msgid "Manage preferences" -msgstr "" - -#: templates/emails/policy-broadcast.php:81 -#: templates/partials/subscribe.php:185 -#, fuzzy -msgid "Unsubscribe" -msgstr "Uitschrijven" - -#: templates/partials/certifications.php:22 -#, fuzzy -msgid "Our active certifications and compliance frameworks demonstrate our commitment to protecting your data." -msgstr "Onze actieve certificeringen en compliance-frameworks laten zien hoe serieus we jouw gegevens beschermen." - -#: templates/partials/certifications.php:59 -#, fuzzy -msgid "Compliant" -msgstr "Compliant" - -#. translators: %s: certification issue date -#: templates/partials/certifications.php:77 -#, fuzzy -#, php-format -msgid "Issued %s" -msgstr "Uitgegeven op %s" - -#. translators: %s: certification expiry date -#: templates/partials/certifications.php:81 -#, fuzzy -#, php-format -msgid "Expires %s" -msgstr "Verloopt op %s" - -#: templates/partials/chat-budget-exhausted.php:18 -msgid "Ask AI is taking a breather" -msgstr "" - -#: templates/partials/chat-budget-exhausted.php:19 -msgid "We've hit the daily question limit. Chat will be back soon — in the meantime, you can still browse the full trust center." -msgstr "" - -#: templates/partials/chat-budget-exhausted.php:22 -msgid "Browse policies" -msgstr "" - -#: templates/partials/chat-budget-exhausted.php:29 -msgid "Contact us" -msgstr "" - -#. translators: %s: company name -#: templates/partials/chat-empty-state.php:29 -#, fuzzy -#, php-format -msgid "Ask about %s's security and compliance" -msgstr "Vraag ons over de beveiliging en compliance van %s" - -#. translators: 1: model identifier, 2: sources summary -#: templates/partials/chat-empty-state.php:37 -#, fuzzy -#, php-format -msgid "Powered by %1$s. Grounded in %2$s." -msgstr "Mogelijk gemaakt door %1$s. Gebaseerd op %2$s." - -#. translators: %s: sources summary -#: templates/partials/chat-empty-state.php:49 -#, fuzzy -#, php-format -msgid "Grounded in %s." -msgstr "Gebaseerd op %s." - -#: templates/partials/chat-empty-state.php:60 -msgid "Conversation" -msgstr "" - -#: templates/partials/data-practices.php:35 -#, fuzzy -msgid "What we collect and how we handle your data." -msgstr "Welke gegevens we verzamelen en hoe we ze gebruiken." - -#. translators: %1$d = number, %2$s = category name -#: templates/partials/data-practices.php:73 -#, fuzzy -#, php-format -msgid "View %1$d more %2$s items" -msgstr "Bekijk nog %1$d %2$s-items" - -#: templates/partials/data-practices.php:110 -#, fuzzy -msgid "Retention" -msgstr "Bewaartermijn" - -#. translators: %d: number of active certifications -#: templates/partials/hero.php:31 -#, fuzzy -#, php-format -msgid "%d Active Certification" -msgid_plural "%d Active Certifications" -msgstr[0] "%d Actieve certificering" -msgstr[1] "%d Actieve certificeringen" - -#: templates/partials/hero.php:38 -#: templates/trust-center.php:20 -#, fuzzy -msgid "Trust Center" -msgstr "Trust Center" - -#: templates/partials/policies.php:21 -#, fuzzy -msgid "Security Policies" -msgstr "Beveiligingsbeleid" - -#: templates/partials/policies.php:22 -#, fuzzy -msgid "Our published security and compliance policies are regularly reviewed and updated." -msgstr "Ons gepubliceerde beveiligings- en compliancebeleid wordt regelmatig herzien en bijgewerkt." - -#: templates/partials/policies.php:39 -#, fuzzy -msgid "Last Updated" -msgstr "Laatst bijgewerkt" - -#. translators: %s: policy version number -#: templates/partials/policies.php:63 -#, fuzzy -#, php-format -msgid "v%s" -msgstr "v%s" - -#: templates/partials/policies.php:67 -#: templates/partials/policy-single.php:119 -#, fuzzy -msgid "Download PDF" -msgstr "Download PDF" - -#. translators: %s: policy title -#: templates/partials/policies.php:73 -#, fuzzy -#, php-format -msgid "View %s" -msgstr "%s bekijken" - -#. translators: %1$s: version number, %2$s: link to current version -#: templates/partials/policy-single.php:66 -#, fuzzy -#, php-format -msgid "You are viewing version %1$s. %2$s" -msgstr "Je bekijkt versie %1$s. %2$s" - -#: templates/partials/policy-single.php:68 -#: templates/partials/policy-single.php:81 -#, fuzzy -msgid "View current version" -msgstr "Huidige versie bekijken" - -#. translators: %1$s: effective date, %2$s: link to previous version -#: templates/partials/policy-single.php:78 -#, fuzzy -#, php-format -msgid "This version takes effect on %1$s. %2$s" -msgstr "Deze versie gaat in op %1$s. %2$s" - -#. translators: %s: policy effective date -#: templates/partials/policy-single.php:104 -#, fuzzy -#, php-format -msgid "Effective: %s" -msgstr "Ingangsdatum: %s" - -#. translators: %s: policy last updated date -#: templates/partials/policy-single.php:111 -#, fuzzy -#, php-format -msgid "Updated: %s" -msgstr "Bijgewerkt: %s" - -#. translators: %d: number of policy versions -#: templates/partials/policy-single.php:135 -#, fuzzy -#, php-format -msgid "Version history (%d)" -msgstr "Versiegeschiedenis (%d)" - -#. translators: %d: version number -#: templates/partials/policy-single.php:150 -#, fuzzy -#, php-format -msgid "v%d" -msgstr "v%d" - -#: templates/partials/subprocessors.php:21 -#, fuzzy -msgid "Third-party services that process data on our behalf, along with their purposes and data handling agreements." -msgstr "Externe diensten die namens ons gegevens verwerken, met hun doel en verwerkersovereenkomsten." - -#: templates/partials/subprocessors.php:53 -#: templates/partials/subprocessors.php:57 -#, fuzzy -msgid "more" -msgstr "meer" - -#: templates/partials/subprocessors.php:64 -#, fuzzy -msgid "Signed" -msgstr "Ondertekend" - -#: templates/partials/subscribe-cta.php:21 -msgid "Stay informed" -msgstr "" - -#: templates/partials/subscribe-cta.php:23 -msgid "Get notified when we update our policies, add subprocessors, or change our compliance posture." -msgstr "" - -#: templates/partials/subscribe-cta.php:29 -#: templates/partials/subscribe.php:30 -#, fuzzy -msgid "Subscribe to updates" -msgstr "Abonneer op updates" - -#: templates/partials/subscribe-cta.php:31 -msgid "RSS Feed" -msgstr "" - -#: templates/partials/subscribe-cta.php:33 -msgid "RSS" -msgstr "" - -#. translators: %s: company name -#: templates/partials/subscribe.php:34 -#, fuzzy -#, php-format -msgid "Get email notifications when %s updates their trust center." -msgstr "Ontvang e-mailmeldingen zodra %s hun Trust Center bijwerkt." - -#: templates/partials/subscribe.php:50 -#, fuzzy -msgid "Email address" -msgstr "E-mailadres" - -#: templates/partials/subscribe.php:52 -msgid "you@company.com" -msgstr "" - -#: templates/partials/subscribe.php:72 -#: templates/partials/subscribe.php:165 -msgid "Notify me about" -msgstr "" - -#: templates/partials/subscribe.php:89 -#: templates/partials/subscribe.php:115 -#, fuzzy -msgid "Subscribe" -msgstr "Abonneren" - -#: templates/partials/subscribe.php:93 -msgid "We will only use your email to send trust center updates. You can unsubscribe at any time." -msgstr "" - -#: templates/partials/subscribe.php:105 -msgid "Subscription confirmed!" -msgstr "" - -#: templates/partials/subscribe.php:106 -msgid "You will now receive email notifications when our trust center is updated." -msgstr "" - -#: templates/partials/subscribe.php:113 -msgid "Invalid or expired link" -msgstr "" - -#: templates/partials/subscribe.php:114 -msgid "This confirmation link is no longer valid. Please subscribe again." -msgstr "" - -#: templates/partials/subscribe.php:126 -msgid "Unsubscribed" -msgstr "" - -#: templates/partials/subscribe.php:127 -msgid "You have been unsubscribed and will no longer receive trust center updates." -msgstr "" - -#: templates/partials/subscribe.php:134 -msgid "Invalid link" -msgstr "" - -#: templates/partials/subscribe.php:135 -msgid "This unsubscribe link is not valid." -msgstr "" - -#: templates/partials/subscribe.php:146 -msgid "Notification preferences" -msgstr "" - -#. translators: %s: email address -#: templates/partials/subscribe.php:150 -#, fuzzy -#, php-format -msgid "Manage notifications for %s." -msgstr "Beheer meldingen voor %s." - -#: templates/partials/subscribe.php:176 -msgid "Save preferences" -msgstr "" - -#: templates/partials/subscribe.php:183 -msgid "Want to stop all notifications?" -msgstr "" - -#: templates/trust-center.php:22 -#, fuzzy -msgid "Transparency and security you can trust." -msgstr "Transparante beveiliging om op te vertrouwen." - -#: templates/trust-center.php:141 -#: templates/trust-center.php:239 -#, fuzzy -msgid "Ask AI" -msgstr "Vraag de AI" - -#: templates/trust-center.php:194 -msgid "Trust center content is being prepared. Check back soon." -msgstr "" - -#. translators: %s: company name -#: templates/trust-center.php:215 -#, fuzzy -#, php-format -msgid "© %1$s %2$s. All rights reserved." -msgstr "© %1$s %2$s. Alle rechten voorbehouden." - -#: templates/trust-center.php:222 -msgid "Powered by OpenTrust" -msgstr "" - diff --git a/templates/chat.php b/templates/chat.php index 457cb91..9694587 100644 --- a/templates/chat.php +++ b/templates/chat.php @@ -42,10 +42,10 @@ // Build nav items so we inherit the same header as the main trust center. $ot_visible = $ot_settings['sections_visible'] ?? []; $ot_nav_items = []; -if (!empty($ot_visible['policies']) && !empty($ot_data['policies'])) $ot_nav_items['policies'] = __('Policies', 'opentrust'); -if (!empty($ot_visible['certifications']) && !empty($ot_data['certifications'])) $ot_nav_items['certifications'] = __('Certifications', 'opentrust'); -if (!empty($ot_visible['subprocessors']) && !empty($ot_data['subprocessors'])) $ot_nav_items['subprocessors'] = __('Subprocessors', 'opentrust'); -if (!empty($ot_visible['data_practices']) && !empty($ot_data['data_practices'])) $ot_nav_items['data-practices'] = __('Data Practices', 'opentrust'); +if (!empty($ot_visible['policies']) && !empty($ot_data['policies'])) $ot_nav_items['policies'] = __('Policies', 'open-trust-center-by-ettic'); +if (!empty($ot_visible['certifications']) && !empty($ot_data['certifications'])) $ot_nav_items['certifications'] = __('Certifications', 'open-trust-center-by-ettic'); +if (!empty($ot_visible['subprocessors']) && !empty($ot_data['subprocessors'])) $ot_nav_items['subprocessors'] = __('Subprocessors', 'open-trust-center-by-ettic'); +if (!empty($ot_visible['data_practices']) && !empty($ot_data['data_practices'])) $ot_nav_items['data-practices'] = __('Data Practices', 'open-trust-center-by-ettic'); $ot_contact_has_content = (bool) ( trim((string) ($ot_settings['company_description'] ?? '')) || trim((string) ($ot_settings['dpo_name'] ?? '')) @@ -57,8 +57,8 @@ || trim((string) ($ot_settings['company_registration'] ?? '')) || trim((string) ($ot_settings['vat_number'] ?? '')) ); -if (!empty($ot_visible['contact']) && $ot_contact_has_content) $ot_nav_items['contact'] = __('Contact', 'opentrust'); -if (!empty($ot_visible['faqs']) && !empty($ot_data['faqs'])) $ot_nav_items['faqs'] = __('FAQ', 'opentrust'); +if (!empty($ot_visible['contact']) && $ot_contact_has_content) $ot_nav_items['contact'] = __('Contact', 'open-trust-center-by-ettic'); +if (!empty($ot_visible['faqs']) && !empty($ot_data['faqs'])) $ot_nav_items['faqs'] = __('FAQ', 'open-trust-center-by-ettic'); ?> > @@ -67,7 +67,7 @@ <?php echo esc_html(sprintf( /* translators: %s: company name */ - __('Ask %s — Trust Center', 'opentrust'), + __('Ask %s — Trust Center', 'open-trust-center-by-ettic'), $ot_company_name ?: get_bloginfo('name') )); ?> @@ -97,9 +97,9 @@ - + - - + - - - - - + + + + + @@ -86,7 +86,7 @@ -
    +
    • @@ -96,16 +96,16 @@
+ printf(esc_html__('v%s', 'open-trust-center-by-ettic'), esc_html((string) $ot_policy['version'])); ?> diff --git a/templates/partials/policy-single.php b/templates/partials/policy-single.php index 61f1a64..5c54916 100644 --- a/templates/partials/policy-single.php +++ b/templates/partials/policy-single.php @@ -33,7 +33,7 @@ $ot_current_url = trailingslashit($ot_base_url) . 'policy/' . $ot_policy->post_name . '/'; ?> - - - - - - - + + + + + + @@ -50,18 +50,18 @@
v post_modified))); ?>
v post_modified))); ?> - - + +  |  - - + +
@@ -113,7 +113,7 @@ + echo esc_attr(sprintf(__('View %s', 'open-trust-center-by-ettic'), $ot_policy['title'])); ?>">→
- + - + - + diff --git a/templates/trust-center.php b/templates/trust-center.php index b399e28..4ad3080 100644 --- a/templates/trust-center.php +++ b/templates/trust-center.php @@ -16,9 +16,9 @@ $ot_hsl = $ot_data['hsl']; $ot_view = $ot_data['view'] ?? 'main'; -$ot_page_title = (string) (($ot_settings['page_title'] ?? '') ?: __('Trust Center', 'opentrust')); +$ot_page_title = (string) (($ot_settings['page_title'] ?? '') ?: __('Trust Center', 'open-trust-center-by-ettic')); $ot_company_name = (string) ($ot_settings['company_name'] ?? ''); -$ot_tagline = (string) (($ot_settings['tagline'] ?? '') ?: __('Transparency and security you can trust.', 'opentrust')); +$ot_tagline = (string) (($ot_settings['tagline'] ?? '') ?: __('Transparency and security you can trust.', 'open-trust-center-by-ettic')); $ot_logo_url = $ot_data['logo_url'] ?? ''; $ot_base_url = $ot_data['base_url'] ?? '/'; @@ -98,20 +98,20 @@ - + -