Ettic Docs
OpenTrustDevelopers

Post types & meta

Five custom post types and every _ot_* postmeta key, by content type.

OpenTrust registers five custom post types. All five have:

  • public => true (so language plugins discover them).
  • publicly_queryable => false, exclude_from_search => true, has_archive => false, rewrite => false (so theme-rendered single-views never trigger).
  • show_in_menu => 'opentrust' (so they appear under the top-level OpenTrust menu).

Public-facing rendering happens exclusively through OpenTrust's own template_redirect dispatcher. Direct URL access via ?p=… returns a 404 by design.

No taxonomies. Categorisation is done with a postmeta enum on each CPT.

Common to every CPT

_ot_uuid: stable cross-site identity (UUID v4). Auto-stamped on every save by OpenTrust_CPT::ensure_uuid(). Used by the import/export layer to match records across environments.

The v1 → v2 schema upgrade back-fills _ot_uuid on every existing post via OpenTrust::backfill_uuids() on init.

ot_policy

Policies. Block editor enabled with a curated allowed-blocks set: paragraph, heading, list, table, quote, separator, image, code, details.

Public URL: /{slug}/policy/{post_slug}/ and historical versions at /{slug}/policy/{post_slug}/version/{n}/.

Meta keyTypePurpose
_ot_versionintCurrent version number, auto-incremented when "Publish new version" is ticked on save.
_ot_version_summarystringOptional one-line "what changed" note for the current version.
_ot_policy_ref_idstringInternal policy reference ID (e.g. SEC-001).
_ot_policy_categoryenumOne of security, privacy, compliance, operational, other.
_ot_policy_effective_datedateYYYY-MM-DD.
_ot_policy_review_datedateYYYY-MM-DD.
_ot_policy_sort_orderintSort order within category on the public page.
_ot_policy_citationsarrayRepeater of [ ['name' => 'SOC 2'], ['name' => 'GDPR'], ... ]. Renders as framework citation pills.
_ot_policy_attachment_idintOptional attachment ID for a PDF download.
_ot_policy_chat_summarystringPer-locale 2-3 sentence routing summary used by the AI chat corpus index. Generated by OpenTrust_Chat_Summarizer.
_ot_policy_chat_summary_updated_atdatetimeWhen the summary was last regenerated.
_ot_policy_chat_summary_originenumauto (generated by AI) or manual (admin-edited).

ot_certification

Compliance certifications. Title-only, no editor.

Meta keyTypePurpose
_ot_cert_typeenumcertified (formal cert) or compliant (alignment without a cert).
_ot_cert_statusenumactive, in_progress, expired. Drives the status badge colour.
_ot_cert_issuing_bodystringFree-form, e.g. "Schellman" or "BSI".
_ot_cert_issue_datedateYYYY-MM-DD.
_ot_cert_expiry_datedateYYYY-MM-DD.
_ot_cert_badge_idintOptional attachment ID for the badge image.
_ot_cert_artifact_idintOptional attachment ID for the audit report PDF.
_ot_cert_descriptionstringTwo or three sentences explaining the scope.

ot_subprocessor

Third-party services that process customer data on your behalf. Title-only.

Meta keyTypePurpose
_ot_sub_purposestringWhy this vendor is used.
_ot_sub_data_processedstringWhat categories of data flow to this vendor.
_ot_sub_countrystringCountry of legal establishment (e.g. "United States").
_ot_sub_websiteurlVendor's website.
_ot_sub_dpa_signedboolWhether you have a signed DPA on file.

ot_data_practice

GDPR Article 30 rows. Title-only.

Meta keyTypePurpose
_ot_dp_data_itemsstring[]Repeater of data fields collected (e.g. ['email', 'IP address', 'browser type']).
_ot_dp_purposestringWhy this data is collected and processed.
_ot_dp_legal_basisenumOne of consent, contract, legitimate_interest, legal_obligation, vital_interest, public_interest.
_ot_dp_retention_periodstringFree-form (e.g. "24 months", "Until contract end").
_ot_dp_shared_withstring[]Repeater of recipient categories.
_ot_dp_sort_orderintSort order on the public page.
_ot_dp_collectedboolGrid toggle.
_ot_dp_storedboolGrid toggle.
_ot_dp_sharedboolGrid toggle.
_ot_dp_soldboolGrid toggle. Renders the "we sell" indicator.
_ot_dp_encryptedboolGrid toggle.

ot_faq

Trust-center FAQs. Block editor enabled, plus page-attributes for menu_order-based sorting.

Meta keyTypePurpose
_ot_faq_related_policyintOptional ot_policy post ID to link from the FAQ.
_ot_seededbooltrue if the FAQ was inserted by the first-install seeder. Used to identify defaults if you want to remove them all programmatically.
_ot_seed_slugstringThe catalog seed slug (e.g. data-hosting) for FAQs that came from the seeder.

Sort order: standard WordPress menu_order via the Page Attributes → Order sidebar field.

Querying OpenTrust content

Use WP_Query with the relevant post_type. The repository class also offers ready-made fetch methods that handle locale-awareness and returns sanitized arrays:

$policies = OpenTrust_Repository::instance()->fetch_policies();
$certs    = OpenTrust_Repository::instance()->fetch_certifications();

See Programmatic API → Repository for the full read-side surface.

Direct database mutation

Allowed but strongly discouraged. If you need to bulk-update OpenTrust content, prefer:

  • wp_update_post() with the right post_type. The standard WordPress hooks fire and the OpenTrust cache invalidator runs automatically.
  • update_post_meta() for individual meta keys. The _ot_uuid postmeta will not be regenerated; if you're cloning a post, also clone or regenerate the UUID.

Direct wpdb->query() writes that bypass the WordPress hook system will leave the OpenTrust cache stale and the chat corpus out of sync. If you must do this, call OpenTrust::instance()->invalidate_cache() afterwards.

On this page