Skip to content

fix: rename CPT slugs to opentr_* with v4 migration#21

Merged
nolderoos merged 4 commits into
mainfrom
fix/cpt-prefix-rename
May 14, 2026
Merged

fix: rename CPT slugs to opentr_* with v4 migration#21
nolderoos merged 4 commits into
mainfrom
fix/cpt-prefix-rename

Conversation

@nolderoos
Copy link
Copy Markdown
Collaborator

@nolderoos nolderoos commented May 13, 2026

Summary

  • Renames the five CPTs (ot_policy, ot_certification, ot_subprocessor, ot_data_practice, ot_faq) to opentr_* to satisfy the wp.org ≥4-char prefix rule. opentr_ is the reviewer's own example and the only candidate that survives WP's hard 20-char register_post_type cap on every slug.
  • Adds a v3 → v4 schema migration in OpenTrust::maybe_upgrade() that rewrites wp_posts.post_type for existing rows, with per-row clean_post_cache() and an explicit chat-corpus invalidate.
  • Guards the activation hook's opentrust_db_version stamp so it only runs on a true first install — fixes the deactivate → upload zip → reactivate upgrade path that would otherwise skip the rename and orphan existing rows.
  • Adds back-compat: OpenTrust_CPT::LEGACY_MAP, OpenTrust_IO::remap_legacy_cpt_keys() for legacy export archives, and a belt-and-suspenders legacy-slug list in uninstall.php.
  • Updates wpml-config.xml <custom-type> entries.
  • POT regenerated (line-number drift only — no msgid changes; existing PO/MO remain valid).

Test plan

  • Fresh activate: CPTs register under opentr_*; opentrust_db_version stamps at 4; no migration runs.
  • Upgrade a v1.0.1 install with rows: deactivate → upload v1.1 zip → reactivate; verify wp_posts.post_type rewrites on next page load and admin lists still show every row.
  • Same upgrade via wp plugin update (no activation hook fires): verify maybe_upgrade() runs the rename on next request.
  • Import a content ZIP produced before the rename: verify legacy ot_* manifest keys are remapped and posts land under the new slugs.
  • Uninstall on a fresh v4 install: verify no errors despite legacy slugs in the cleanup list.

Closes #20

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Automatic v3→v4 migration that renames legacy content types to the new naming convention during upgrade.
  • Chores

    • Centralized and standardized content-type identifiers across the plugin.
    • Bumped database schema version to 4 and preserved existing installs during activation.
    • Updated translation template and admin-facing documentation/comments to use new type names.
  • Bug Fixes

    • Admin UI behaviors, catalog autofill, imports, and background tasks now target the updated content types.

Review Change Stack

nolderoos and others added 2 commits May 13, 2026 01:13
wp.org reviewer required a 4+ char prefix. Renamed the 5 CPTs from ot_* to opentr_*. Added v3 to v4 migration to rewrite wp_posts.post_type for existing rows. Legacy slugs preserved in OpenTrust_CPT::LEGACY_* and used by the import/export back-compat remap and uninstall cleanup.
…he staleness (#20)

Pass 2 goalkeeper review surfaced three sharp edges in the v3 to v4 rename:

- opentrust.php: the activation hook unconditionally stamped opentrust_db_version on every activation, which would skip the rename on the deactivate-upload-reactivate upgrade path and orphan every existing ot_* row. Stamp on first install only; maybe_upgrade() handles the upgrade path on next init.
- includes/class-opentrust.php: rename_cpt_slugs_v4() now collects affected post IDs before the UPDATE and calls clean_post_cache() per row so the WP_Post object cache does not return stale post_type values after the migration.
- includes/class-opentrust.php: explicitly invalidate the chat corpus transient at the end of maybe_upgrade(); the corpus is locale-keyed and not bound to opentrust_cache_version, so the cache-version bump alone would not bust it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

📝 Walkthrough

Walkthrough

The PR renames five custom post type slugs from the non-compliant 2-character ot_* prefix to the WordPress.org-approved 4-character opentr_* prefix. This includes database schema migration (v3→v4), constant-based architecture refactoring, legacy export data remapping, and plugin lifecycle updates.

Changes

CPT Slug Migration (ot_ → opentr_*)*

Layer / File(s) Summary
CPT Constants, Legacy Mapping, and Taxonomy
includes/class-opentrust-cpt.php
New OpenTrust_CPT class defines canonical opentr_policy, opentr_certification, opentr_subprocessor, opentr_data_practice, opentr_faq constants; introduces legacy LEGACY_* constants and LEGACY_MAP array for v3→v4 migration and back-compat remapping.
Database Schema Upgrade and Version Management
opentrust.php, includes/class-opentrust.php
Database version incremented from 3 to 4. Activation logic preserves existing versions for proper upgrade routing. New rename_cpt_slugs_v4() migration method iterates LEGACY_MAP, updates post_type rows via direct SQL, clears post cache per row, and invalidates chat corpus to rebuild against renamed posts.
CPT Registration and Admin UI Wiring
includes/class-opentrust-cpt.php
Post type registration, admin list-table column hooks, title prompt logic, meta box registration, save routing, and allowed-block guard refactored to use self::* constants instead of hard-coded ot_* strings. FAQ meta box policy query and validation updated to target canonical policy constant.
Data Fetchers, Render Queries, and Catalog Operations
includes/class-opentrust-repository.php, includes/class-opentrust-render.php, includes/class-opentrust-catalog.php
All per-CPT data fetchers and section-to-CPT mappings now use OpenTrust_CPT::* constants for post_type filtering. Catalog FAQ seeding and JS payload builder refactored to reference canonical CPT slugs.
Chat Summarizer Hook Registration and Scheduled Operations
includes/class-opentrust-chat-summarizer.php
Policy post-type targeting refactored from hard-coded ot_policy to OpenTrust_CPT::POLICY in hook registration, cron guard logic, sweep/count queries, and inline documentation.
Import/Export and Legacy Manifest Remapping
includes/class-opentrust-io.php
Internal meta key and post-reference mappings refactored to use OpenTrust_CPT::* constants. New remap_legacy_cpt_keys() method rewrites inbound v1.0.x manifest CPT keys at import time using LEGACY_MAP. Import preview and apply flows call remapping before processing; chat summarizer suppression/restoration updated to use dynamic hook names via constant.
Admin Tools, Labels, Review Components, and Version Meta Box
includes/class-opentrust-admin-tools.php, includes/class-opentrust-admin.php, includes/class-opentrust-admin-review.php, includes/class-opentrust-version.php, assets/js/admin.js
Admin label mapping, post-new catalog autofill gating, milestone notice display, and version history meta box registration all refactored to use OpenTrust_CPT constants for post type comparisons and queries; small doc/comment fixes updated.
Plugin Lifecycle, Uninstall, Internationalization, and Framework Configuration
uninstall.php, wpml-config.xml, includes/data/*-catalog.php, languages/opentrust.pot
Uninstall expanded to delete both legacy ot_* and new opentr_* post types with explanatory comment. WPML configuration updated to register new CPT slugs for translation. Catalog data file documentation corrected to reference new post type names. POT creation timestamp refreshed and source references regenerated to reflect code movement.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 Five slugs shed their short ot_ coats,
Now wearing opentr_ with four-char footnotes,
Manifests remapped and databases aligned,
Constants steer queries so nothing's misdefined,
Hop, migrate, and cache-clean — a tidy new coat!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title directly and concisely describes the main change: renaming CPT slugs from ot_* to opentr_* with a v4 migration step.
Linked Issues check ✅ Passed The PR comprehensively addresses all coding requirements from issue #20: renames five CPT slugs to opentr_* prefix, implements v3→v4 schema migration, adds legacy-slug constants and remap helpers, updates WPML config, and adjusts activation/uninstall logic.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the CPT slug rename and v4 migration requirements. Documentation comments, POT regeneration, and helper methods all support the core objective without unrelated additions.
Docstring Coverage ✅ Passed Docstring coverage is 82.86% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/cpt-prefix-rename

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@includes/class-opentrust-io.php`:
- Around line 427-429: The loop that maps incoming manifest records into $out
uses OpenTrust_CPT::LEGACY_MAP to normalize keys but assigns $recs directly, so
when a legacy and a new key map to the same CPT the latter overwrites the
former; update the foreach over $manifest['records'] to merge arrays into $out
instead of replacing—e.g., for each $cpt/$recs, compute $key =
OpenTrust_CPT::LEGACY_MAP[$cpt] ?? $cpt and then append/array_merge $recs into
existing $out[$key] (initializing it if absent) so records from both keys are
preserved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 05e3089c-7950-4971-845d-0d7171941bc1

📥 Commits

Reviewing files that changed from the base of the PR and between 0a38992 and c4f4d17.

📒 Files selected for processing (20)
  • assets/js/admin.js
  • includes/class-opentrust-admin-review.php
  • includes/class-opentrust-admin-tools.php
  • includes/class-opentrust-admin.php
  • includes/class-opentrust-catalog.php
  • includes/class-opentrust-chat-summarizer.php
  • includes/class-opentrust-cpt.php
  • includes/class-opentrust-io.php
  • includes/class-opentrust-render.php
  • includes/class-opentrust-repository.php
  • includes/class-opentrust-version.php
  • includes/class-opentrust.php
  • includes/data/certification-catalog.php
  • includes/data/data-practice-catalog.php
  • includes/data/faq-catalog.php
  • includes/data/subprocessor-catalog.php
  • languages/opentrust.pot
  • opentrust.php
  • uninstall.php
  • wpml-config.xml

Comment thread includes/class-opentrust-io.php
@nolderoos
Copy link
Copy Markdown
Collaborator Author

nolderoos commented May 13, 2026

v1.1.0 upgrade plan — release notes

Summary. This PR renames five CPT slugs from ot_* to opentr_* to satisfy the wp.org 4-character-prefix rule, and bumps OPENTRUST_DB_VERSION from 3 to 4. The migration is gated entirely on opentrust_db_version, runs on init at priority 5 (before CPTs register at priority 10), and is idempotent so a partial run retries on the next request. Activation is decoupled from migration: the activation hook now only stamps the schema version on a true first install, which means every realistic upgrade path — wp.org auto-update, WP-CLI, manual upload, SFTP — converges on the same maybe_upgrade() code path the next time WordPress hits init.

Scenario walkthrough

1. Fresh install on a clean WordPress. Activation hook fires. register_post_types() runs first so rewrite rules pick up the new slugs, default opentrust_settings is seeded with autoload=no, the chat-log table is created, default FAQs are seeded, and — because get_option('opentrust_db_version', false) returns falseopentrust_db_version is stamped to 4 immediately. On the next init, maybe_upgrade() sees current === 4 and returns early. DB ends up clean, no migration ever runs. No legacy rows exist, so nothing to rename. CPTs render correctly under their new slugs.

2. wp.org background auto-update. No activation hook. Files swap in place; opentrust_db_version is still 3 (or 0 for installs older than v1.0.x, which only existed as v1.0.0/1.0.1 — so realistically 0 since no prior DB version was ever set). On the first request after the swap, OpenTrust::__construct() registers maybe_upgrade at init priority 5. It detects current < 4, calls rename_cpt_slugs_v4() which walks LEGACY_MAP, collects row IDs per old slug, runs $wpdb->update() to flip post_type to the new slug, then clean_post_cache() per ID so any cached WP_Post objects don't return stale ot_* values. Then current < 2 runs backfill_uuids() against the (now-renamed) slugs in OpenTrust_CPT::ALL, and current < 3 reschedules the AI-model cron and back-fills the model snapshot. The opentrust_db_version option is updated to 4, a flush-rewrite transient is set (consumed on init priority 99), the render cache version is bumped, and the chat corpus transient is invalidated. Note on v1.0.x → v1.1.0 specifically: v1.0.x never wrote opentrust_db_version, so current === 0 and the comparator path is "all steps run, in the order v4→v2→v3 as documented." The v4 step must come first because the v1→v2 UUID back-fill queries OpenTrust_CPT::ALL — the new slugs.

3. WP-CLI wp plugin update opentrust. Identical to scenario 2 — no activation hook, files replaced, maybe_upgrade() runs on the next request (which is typically the immediate wp invocation that finishes the update, since WP-CLI fires init to load WordPress). The migration is transactional only at the per-row level; if WP-CLI is interrupted mid-rename, opentrust_db_version stays at 0/3 and the next request retries from the top. Already-renamed rows skip silently because the SELECT ID … WHERE post_type = %s against the legacy slug returns an empty array.

4. Manual "Upload Plugin" (replace flow). WP typically deactivates the plugin during replacement, lands the new files, and lands the user on a screen asking them to click Activate. Mid-upgrade state: the DB still holds ot_* rows; opentrust_db_version is unchanged; CPTs are no longer registered (plugin inactive) so the admin menu is empty and the trust-center URL 404s. On Activate: the activation hook fires, register_post_types() runs against the new slugs (so the activation flush includes the right rewrite rules), the schema-version stamp is skipped because the option already exists, and crons are re-scheduled. Then on the very next request, init priority 5 fires maybe_upgrade() and the rename runs. Visible to the operator: CPT submenus reappear immediately on activation; existing rows reappear in admin lists on the request after activation (the one where maybe_upgrade runs). In practice this is the same page-load because WP redirects after Activate.

5. SFTP file replacement → user clicks Activate. Behaviourally identical to scenario 4.

6. Upgrade from a hypothetical pre-v3 install (v1 → v4 jump). maybe_upgrade() walks every gate it has crossed: < 4 runs first (rename), then < 2 runs UUID back-fill against the now-renamed slugs, then < 3 runs AI cron + model snapshot. This ordering is the load-bearing reason the v4 step is listed first in the method despite being numerically last.

7. Re-run after a fatal interruption. Because opentrust_db_version is only updated to 4 at the very end of maybe_upgrade(), any fatal mid-run leaves it at the prior value. The next request re-enters all current < N branches. rename_cpt_slugs_v4() is naturally idempotent (already-renamed rows don't match the legacy WHERE). backfill_uuids() filters by _ot_uuid NOT EXISTS. backfill_model_snapshot() is a no-op if no provider/model is configured. Safe to re-run by wp eval 'OpenTrust::instance()->maybe_upgrade();' if needed.

Operator FAQ

  • Will my existing content survive the update? Yes. The migration only rewrites wp_posts.post_type for the five renamed CPTs. Post IDs, titles, content, revisions, post meta (all _ot_* keys are unchanged), WPML/Polylang translation linkage (keyed by post ID), and permalinks are all preserved.
  • Do I need to take a backup? Always advisable before any DB-mutating plugin update, but the migration is gated and idempotent. There is no destructive step.
  • What if I roll back to 1.0.1 after upgrading? Rolling back files without restoring the DB leaves your CPT rows under opentr_* slugs while v1.0.1 code only knows ot_* — admin lists and the trust center will appear empty. The data isn't lost; either restore from a DB backup or run a one-shot reverse UPDATE on wp_posts.post_type.
  • Legacy 1.0.x export ZIP — does it still import? Yes. OpenTrust_IO::remap_legacy_cpt_keys() rewrites the top-level records keys via LEGACY_MAP on both preview_import() and apply_content_import(). Cross-CPT refs in record bodies are UUID-based, so they resolve correctly post-remap.
  • Third-party code referencing ot_policy etc.? Will break. The constants OpenTrust_CPT::LEGACY_* exist only for the migration and import remap, not as runtime aliases. Update integrations to use OpenTrust_CPT::POLICY / opentr_policy.

Rollback plan

If a site reports CPTs missing post-update: confirm opentrust_db_version value, check wp_posts for surviving ot_* rows, and (a) re-run maybe_upgrade() via wp eval if version is still < 4, or (b) restore DB from pre-update backup if the migration partially completed and rolled forward the option. A full restore is the safest answer for production.

What to watch in production

  • opentrust_db_version advances to 4 on the first authenticated request after upgrade
  • Admin submenus for Policies / Certifications / Subprocessors / Data Practices / FAQs show pre-existing rows
  • Trust-center page still renders the same sections and items
  • Policy version permalinks (/trust-center/policy/{slug}/version/{n}/) still resolve (rewrite flush is queued via opentrust_flush_rewrite transient)
  • Chat corpus rebuilds cleanly on the first chat request (transient invalidated explicitly in maybe_upgrade)
  • WPML/Polylang translation pairings intact (linkage is by post ID, not slug)
  • Heads-up: OPENTRUST_VERSION in opentrust.php and Stable tag in readme.txt are still 1.0.1. Bump these to 1.1.0 at release-tag time.

…20)

Adds @deprecated PHPDoc tags so IDEs and static analyzers flag the four
pieces of v1.0.x → v1.1.0 upgrade scaffolding when 2.0.0 cleanup happens:

- OpenTrust_CPT::LEGACY_* constants + LEGACY_MAP
- OpenTrust::rename_cpt_slugs_v4()
- OpenTrust_IO::remap_legacy_cpt_keys()
- uninstall.php legacy ot_* slug fallback list

No runtime behavior change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Line-reference shifts only; no msgid changes, so existing PO/MO files remain valid.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nolderoos nolderoos merged commit 8d5cbb2 into main May 14, 2026
11 checks passed
nolderoos added a commit that referenced this pull request May 14, 2026
…dundant v4 DB-version comment superseded by #21 migration
@nolderoos nolderoos deleted the fix/cpt-prefix-rename branch May 14, 2026 12:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rename CPT slugs to use a 4+ character prefix (opentr_)

1 participant