Resolves the rewrite slug collision that was 404'ing all 89 production peptide detail pages. PR Core v0.1.1 registered an empty pr_peptide CPT claiming /peptides/%postname%/; WP's rewrite resolver picked it over PSA's populated peptide CPT. This release consolidates both registrations onto a single peptide CPT owned by PR Core. PSA v4.5.0 drops its registration in favor of this one. ## Contract (per CTO msg 02) - POST_TYPE: pr_peptide -> peptide - TAX_CATEGORY: pr_peptide_category -> peptide_category - TAX_FAMILY const removed (pr_peptide_family was never populated) - CPT + taxonomy registration guarded with post_type_exists() / taxonomy_exists() so deploy order between PR Core and PSA is forgiving - Args harmonized as superset of PSA + prior PR Core (thumbnail added to supports; capability_type + map_meta_cap preserved) - Activator: flush_rewrite_rules(false) on activation; new maybe_flush_on_version_change() handler hooked at init:999 for in-place updates that bypass the activation hook (e.g. SCP deploys) - uninstall.php: blanket DELETE replaced with JOIN on _pr_core_authored so PSA-authored peptide posts (the 89 canonical monographs) are never destroyed; peptide_category terms preserved (shared ownership) - Scrub scope: narrow — CPT-slug-derived identifiers only; class names, file names, PR_CORE_* constants, pr_core_* options, and pr-core/v1 REST namespace remain ## Docs - ARCHITECTURE.md: new Key Decision #7 (v0.2.0 consolidation) and §2.9 Uninstall specification - CONVENTIONS.md: CPT Ownership rule + _pr_core_authored flag contract ## Tests - Lightweight harness (tests/bootstrap.php) that stubs the handful of WP functions exercised by the CPT class - tests/unit/test-peptide-cpt.php asserts: constants match contract, TAX_FAMILY is removed, guard no-ops when post_type_exists/taxonomy_exists returns true, args payload shape (thumbnail in supports, rewrite slug, REST namespace), hooks wired - CI: new 'Unit tests (lightweight, no PHPUnit)' step in lint-php job, runs across PHP 8.1/8.2/8.3. Full PHPUnit + wp-env harness is a follow-up Refs: convo/prcore/threads/2026-04-peptides-cpt-collision/02-cto-correction.md
92 lines
4.0 KiB
PHP
92 lines
4.0 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Typed data-transfer object for a peptide record.
|
|
*
|
|
* What: Immutable value object wrapping a peptide post + its meta fields.
|
|
* Who calls it: PR_Core_Peptide_Repository returns these; consumers read them.
|
|
* Dependencies: None.
|
|
*
|
|
* @see cpt/class-pr-core-peptide-cpt.php — Meta field definitions.
|
|
* @see repositories/class-pr-core-peptide-repository.php — Creates these from WP_Post.
|
|
*/
|
|
class PR_Core_Peptide_DTO {
|
|
|
|
public readonly int $id;
|
|
public readonly string $title;
|
|
public readonly string $slug;
|
|
public readonly string $content;
|
|
public readonly string $excerpt;
|
|
public readonly string $status;
|
|
public readonly string $display_name;
|
|
/** @var string[] */
|
|
public readonly array $aliases;
|
|
public readonly string $molecular_formula;
|
|
public readonly float $molecular_weight;
|
|
public readonly string $cas_number;
|
|
public readonly string $drugbank_id;
|
|
public readonly string $chembl_id;
|
|
public readonly string $evidence_strength;
|
|
public readonly string $editorial_review_status;
|
|
public readonly string $last_editorial_review_at;
|
|
public readonly int $medical_editor_id;
|
|
/** @var string[] Category term names. */
|
|
public readonly array $categories;
|
|
/** @var string[] Family term names. */
|
|
public readonly array $families;
|
|
|
|
/**
|
|
* @param array<string, mixed> $data Associative array of peptide fields.
|
|
*/
|
|
public function __construct( array $data ) {
|
|
$this->id = (int) ( $data['id'] ?? 0 );
|
|
$this->title = (string) ( $data['title'] ?? '' );
|
|
$this->slug = (string) ( $data['slug'] ?? '' );
|
|
$this->content = (string) ( $data['content'] ?? '' );
|
|
$this->excerpt = (string) ( $data['excerpt'] ?? '' );
|
|
$this->status = (string) ( $data['status'] ?? 'draft' );
|
|
$this->display_name = (string) ( $data['display_name'] ?? '' );
|
|
$this->aliases = (array) ( $data['aliases'] ?? [] );
|
|
$this->molecular_formula = (string) ( $data['molecular_formula'] ?? '' );
|
|
$this->molecular_weight = (float) ( $data['molecular_weight'] ?? 0 );
|
|
$this->cas_number = (string) ( $data['cas_number'] ?? '' );
|
|
$this->drugbank_id = (string) ( $data['drugbank_id'] ?? '' );
|
|
$this->chembl_id = (string) ( $data['chembl_id'] ?? '' );
|
|
$this->evidence_strength = (string) ( $data['evidence_strength'] ?? 'preclinical' );
|
|
$this->editorial_review_status = (string) ( $data['editorial_review_status'] ?? 'draft' );
|
|
$this->last_editorial_review_at = (string) ( $data['last_editorial_review_at'] ?? '' );
|
|
$this->medical_editor_id = (int) ( $data['medical_editor_id'] ?? 0 );
|
|
$this->categories = (array) ( $data['categories'] ?? [] );
|
|
$this->families = (array) ( $data['families'] ?? [] );
|
|
}
|
|
|
|
/**
|
|
* Convert to associative array (e.g., for REST API responses).
|
|
*
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function to_array(): array {
|
|
return [
|
|
'id' => $this->id,
|
|
'title' => $this->title,
|
|
'slug' => $this->slug,
|
|
'excerpt' => $this->excerpt,
|
|
'display_name' => $this->display_name,
|
|
'aliases' => $this->aliases,
|
|
'molecular_formula' => $this->molecular_formula,
|
|
'molecular_weight' => $this->molecular_weight,
|
|
'cas_number' => $this->cas_number,
|
|
'drugbank_id' => $this->drugbank_id,
|
|
'chembl_id' => $this->chembl_id,
|
|
'evidence_strength' => $this->evidence_strength,
|
|
'editorial_review_status' => $this->editorial_review_status,
|
|
'last_editorial_review_at' => $this->last_editorial_review_at,
|
|
'medical_editor_id' => $this->medical_editor_id,
|
|
'categories' => $this->categories,
|
|
'families' => $this->families,
|
|
'url' => get_permalink( $this->id ),
|
|
];
|
|
}
|
|
}
|