feat: add browsable peptide directory with category filtering, REST API, and extended meta fields (v4.3.0)

Adds [peptide_directory] shortcode with card grid, category taxonomy (8 terms),
search, pagination, detail modal, and /v1/compounds REST endpoint. Includes 9
new meta fields (half-life, stability, solubility, etc.), admin data tools for
migration/re-enrichment, integration hooks for cross-plugin extensibility,
dark mode support, and full uninstall cleanup. Refactors AI generator into
PSA_OpenRouter + PSA_KB_Builder classes. Adds PHPUnit tests for PostType and
Directory classes. Fixes QA findings: dead JS selector, renderError loading
state, numeric meta validation, prepared SQL in uninstall.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
peptiderepo
2026-04-13 21:30:11 +07:00
parent 0fa2707163
commit ed65b6ab90
28 changed files with 3380 additions and 783 deletions

View File

@@ -1,4 +1,5 @@
<?php
declare( strict_types=1 );
/**
* Tracks API usage costs and enforces monthly budget limits.
*
@@ -20,7 +21,7 @@ class PSA_Cost_Tracker {
* Create the API logs table if it doesn't exist.
* Uses dbDelta for safe schema updates.
*/
public static function create_table() {
public static function create_table(): void {
global $wpdb;
$table_name = $wpdb->prefix . 'psa_api_logs';
@@ -68,7 +69,7 @@ class PSA_Cost_Tracker {
* }
* @return int|false Insert ID or false on error.
*/
public static function log_api_call( $data ) {
public static function log_api_call( array $data ) {
global $wpdb;
$table_name = $wpdb->prefix . 'psa_api_logs';
@@ -126,7 +127,7 @@ class PSA_Cost_Tracker {
* @param int|null $month Month (defaults to current month).
* @return float Total USD spent in the month.
*/
public static function get_monthly_spend( $year = null, $month = null ) {
public static function get_monthly_spend( ?int $year = null, ?int $month = null ): float {
global $wpdb;
if ( null === $year ) {
@@ -165,7 +166,7 @@ class PSA_Cost_Tracker {
* @param int|null $month Month (defaults to current month).
* @return int Total tokens used in the month.
*/
public static function get_monthly_tokens( $year = null, $month = null ) {
public static function get_monthly_tokens( ?int $year = null, ?int $month = null ): int {
global $wpdb;
if ( null === $year ) {
@@ -203,7 +204,7 @@ class PSA_Cost_Tracker {
*
* @return bool True if budget exceeded, false otherwise.
*/
public static function is_budget_exceeded() {
public static function is_budget_exceeded(): bool {
$settings = get_option( 'psa_settings', array() );
$budget = floatval( $settings['monthly_budget'] ?? PSA_Config::DEFAULT_MONTHLY_BUDGET );
@@ -222,7 +223,7 @@ class PSA_Cost_Tracker {
* @param int $limit Maximum number of logs to return.
* @return array Array of log objects.
*/
public static function get_recent_logs( $limit = 20 ) {
public static function get_recent_logs( int $limit = 20 ): array {
global $wpdb;
$table_name = $wpdb->prefix . 'psa_api_logs';
@@ -248,7 +249,7 @@ class PSA_Cost_Tracker {
* @param int $completion_tokens Tokens in completion.
* @return float Estimated cost in USD.
*/
public static function estimate_cost( $model, $prompt_tokens, $completion_tokens ) {
public static function estimate_cost( string $model, int $prompt_tokens, int $completion_tokens ): float {
// Known model pricing per 1 million tokens (input, output).
$pricing = array(
'google/gemini-2.5-flash' => array( 0.15, 0.60 ),
@@ -275,7 +276,7 @@ class PSA_Cost_Tracker {
/**
* Drop the API logs table during uninstall.
*/
public static function drop_table() {
public static function drop_table(): void {
global $wpdb;
$table_name = $wpdb->prefix . 'psa_api_logs';