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 key | Type | Purpose |
|---|---|---|
_ot_version | int | Current version number, auto-incremented when "Publish new version" is ticked on save. |
_ot_version_summary | string | Optional one-line "what changed" note for the current version. |
_ot_policy_ref_id | string | Internal policy reference ID (e.g. SEC-001). |
_ot_policy_category | enum | One of security, privacy, compliance, operational, other. |
_ot_policy_effective_date | date | YYYY-MM-DD. |
_ot_policy_review_date | date | YYYY-MM-DD. |
_ot_policy_sort_order | int | Sort order within category on the public page. |
_ot_policy_citations | array | Repeater of [ ['name' => 'SOC 2'], ['name' => 'GDPR'], ... ]. Renders as framework citation pills. |
_ot_policy_attachment_id | int | Optional attachment ID for a PDF download. |
_ot_policy_chat_summary | string | Per-locale 2-3 sentence routing summary used by the AI chat corpus index. Generated by OpenTrust_Chat_Summarizer. |
_ot_policy_chat_summary_updated_at | datetime | When the summary was last regenerated. |
_ot_policy_chat_summary_origin | enum | auto (generated by AI) or manual (admin-edited). |
ot_certification
Compliance certifications. Title-only, no editor.
| Meta key | Type | Purpose |
|---|---|---|
_ot_cert_type | enum | certified (formal cert) or compliant (alignment without a cert). |
_ot_cert_status | enum | active, in_progress, expired. Drives the status badge colour. |
_ot_cert_issuing_body | string | Free-form, e.g. "Schellman" or "BSI". |
_ot_cert_issue_date | date | YYYY-MM-DD. |
_ot_cert_expiry_date | date | YYYY-MM-DD. |
_ot_cert_badge_id | int | Optional attachment ID for the badge image. |
_ot_cert_artifact_id | int | Optional attachment ID for the audit report PDF. |
_ot_cert_description | string | Two or three sentences explaining the scope. |
ot_subprocessor
Third-party services that process customer data on your behalf. Title-only.
| Meta key | Type | Purpose |
|---|---|---|
_ot_sub_purpose | string | Why this vendor is used. |
_ot_sub_data_processed | string | What categories of data flow to this vendor. |
_ot_sub_country | string | Country of legal establishment (e.g. "United States"). |
_ot_sub_website | url | Vendor's website. |
_ot_sub_dpa_signed | bool | Whether you have a signed DPA on file. |
ot_data_practice
GDPR Article 30 rows. Title-only.
| Meta key | Type | Purpose |
|---|---|---|
_ot_dp_data_items | string[] | Repeater of data fields collected (e.g. ['email', 'IP address', 'browser type']). |
_ot_dp_purpose | string | Why this data is collected and processed. |
_ot_dp_legal_basis | enum | One of consent, contract, legitimate_interest, legal_obligation, vital_interest, public_interest. |
_ot_dp_retention_period | string | Free-form (e.g. "24 months", "Until contract end"). |
_ot_dp_shared_with | string[] | Repeater of recipient categories. |
_ot_dp_sort_order | int | Sort order on the public page. |
_ot_dp_collected | bool | Grid toggle. |
_ot_dp_stored | bool | Grid toggle. |
_ot_dp_shared | bool | Grid toggle. |
_ot_dp_sold | bool | Grid toggle. Renders the "we sell" indicator. |
_ot_dp_encrypted | bool | Grid toggle. |
ot_faq
Trust-center FAQs. Block editor enabled, plus page-attributes for menu_order-based sorting.
| Meta key | Type | Purpose |
|---|---|---|
_ot_faq_related_policy | int | Optional ot_policy post ID to link from the FAQ. |
_ot_seeded | bool | true if the FAQ was inserted by the first-install seeder. Used to identify defaults if you want to remove them all programmatically. |
_ot_seed_slug | string | The 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 rightpost_type. The standard WordPress hooks fire and the OpenTrust cache invalidator runs automatically.update_post_meta()for individual meta keys. The_ot_uuidpostmeta 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.