diff --git a/includes/class-psa-admin-page.php b/includes/class-psa-admin-page.php
index 4250995..383335c 100644
--- a/includes/class-psa-admin-page.php
+++ b/includes/class-psa-admin-page.php
@@ -29,10 +29,14 @@ class PSA_Admin_Page {
}
wp_enqueue_script( 'psa-batch-enrich', PSA_PLUGIN_URL . 'assets/js/psa-batch-enrich.js', array( 'jquery' ), PSA_VERSION, true );
- wp_localize_script( 'psa-batch-enrich', 'psaBatchEnrich', array(
- 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
- 'nonce' => wp_create_nonce( 'psa_batch_enrich' ),
- ) );
+ wp_localize_script(
+ 'psa-batch-enrich',
+ 'psaBatchEnrich',
+ array(
+ 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
+ 'nonce' => wp_create_nonce( 'psa_batch_enrich' ),
+ )
+ );
}
// ── Field renderers ─────────────────────────────────────────────────
@@ -119,7 +123,11 @@ class PSA_Admin_Page {
@@ -216,6 +224,7 @@ class PSA_Admin_Page {
- array( __CLASS__, 'sanitize_settings' ),
- ) );
+ register_setting(
+ 'psa_settings_group',
+ 'psa_settings',
+ array(
+ 'sanitize_callback' => array( __CLASS__, 'sanitize_settings' ),
+ )
+ );
add_settings_section( 'psa_ai_section', __( 'OpenRouter API Settings', 'peptide-search-ai' ), array( 'PSA_Admin_Page', 'render_section_description' ), 'peptide-search-ai' );
add_settings_field( 'api_key', __( 'API Key', 'peptide-search-ai' ), array( 'PSA_Admin_Page', 'render_api_key_field' ), 'peptide-search-ai', 'psa_ai_section' );
@@ -95,18 +99,27 @@ class PSA_Admin {
if ( 'migrate_categories' === $action && wp_verify_nonce( $nonce, 'psa_migrate_categories' ) ) {
self::run_category_migration();
- add_action( 'admin_notices', function () {
- echo '
' . esc_html__( 'Category migration completed.', 'peptide-search-ai' ) . '
';
- } );
+ add_action(
+ 'admin_notices',
+ function () {
+ echo '
' . esc_html__( 'Category migration completed.', 'peptide-search-ai' ) . '
';
+ }
+ );
}
if ( 'reenrich' === $action && wp_verify_nonce( $nonce, 'psa_reenrich' ) ) {
$queued = self::queue_reenrichment();
- add_action( 'admin_notices', function () use ( $queued ) {
- echo '
' . esc_html( sprintf(
- __( '%d peptides queued for re-enrichment.', 'peptide-search-ai' ), $queued
- ) ) . '
';
- } );
+ add_action(
+ 'admin_notices',
+ function () use ( $queued ) {
+ echo '
' . esc_html(
+ sprintf(
+ __( '%d peptides queued for re-enrichment.', 'peptide-search-ai' ),
+ $queued
+ )
+ ) . '
';
+ }
+ );
}
}
@@ -117,12 +130,14 @@ class PSA_Admin {
* Idempotent — safe to run multiple times.
*/
private static function run_category_migration(): void {
- $posts = get_posts( array(
- 'post_type' => 'peptide',
- 'post_status' => array( 'publish', 'draft' ),
- 'posts_per_page' => -1,
- 'fields' => 'ids',
- ) );
+ $posts = get_posts(
+ array(
+ 'post_type' => 'peptide',
+ 'post_status' => array( 'publish', 'draft' ),
+ 'posts_per_page' => -1,
+ 'fields' => 'ids',
+ )
+ );
foreach ( $posts as $post_id ) {
$terms = wp_get_object_terms( $post_id, 'peptide_category' );
@@ -199,17 +214,25 @@ class PSA_Admin {
* @return int Number of peptides queued.
*/
private static function queue_reenrichment(): int {
- $posts = get_posts( array(
- 'post_type' => 'peptide',
- 'post_status' => 'publish',
- 'posts_per_page' => -1,
- 'fields' => 'ids',
- 'meta_query' => array(
- 'relation' => 'OR',
- array( 'key' => 'psa_half_life', 'compare' => 'NOT EXISTS' ),
- array( 'key' => 'psa_half_life', 'value' => '' ),
- ),
- ) );
+ $posts = get_posts(
+ array(
+ 'post_type' => 'peptide',
+ 'post_status' => 'publish',
+ 'posts_per_page' => -1,
+ 'fields' => 'ids',
+ 'meta_query' => array(
+ 'relation' => 'OR',
+ array(
+ 'key' => 'psa_half_life',
+ 'compare' => 'NOT EXISTS',
+ ),
+ array(
+ 'key' => 'psa_half_life',
+ 'value' => '',
+ ),
+ ),
+ )
+ );
$daily_key = 'psa_daily_gen_' . gmdate( 'Y-m-d' );
$daily_count = (int) get_transient( $daily_key );
@@ -226,7 +249,12 @@ class PSA_Admin {
}
update_post_meta( $post_id, 'psa_source', 'pending' );
- wp_update_post( array( 'ID' => $post_id, 'post_status' => 'draft' ) );
+ wp_update_post(
+ array(
+ 'ID' => $post_id,
+ 'post_status' => 'draft',
+ )
+ );
update_post_meta( $post_id, 'psa_generation_started', time() );
$args = array( $post_id, $post->post_title );
@@ -234,7 +262,7 @@ class PSA_Admin {
// Stagger 30s apart to avoid rate-limit hammering.
wp_schedule_single_event( time() + ( $queued * 30 ), 'psa_generate_peptide_background', $args );
}
- $queued++;
+ ++$queued;
}
set_transient( $daily_key, $daily_count + $queued, DAY_IN_SECONDS );
@@ -262,29 +290,38 @@ class PSA_Admin {
// ── Backward-compatible proxies (rendering moved to PSA_Admin_Page) ─
/** @see PSA_Admin_Page::enqueue_batch_scripts() */
- public static function enqueue_batch_scripts( string $hook ): void { PSA_Admin_Page::enqueue_batch_scripts( $hook ); }
+ public static function enqueue_batch_scripts( string $hook ): void {
+ PSA_Admin_Page::enqueue_batch_scripts( $hook ); }
/** @see PSA_Admin_Page::render_section_description() */
- public static function render_section_description(): void { PSA_Admin_Page::render_section_description(); }
+ public static function render_section_description(): void {
+ PSA_Admin_Page::render_section_description(); }
/** @see PSA_Admin_Page::render_api_key_field() */
- public static function render_api_key_field(): void { PSA_Admin_Page::render_api_key_field(); }
+ public static function render_api_key_field(): void {
+ PSA_Admin_Page::render_api_key_field(); }
/** @see PSA_Admin_Page::render_model_field() */
- public static function render_model_field(): void { PSA_Admin_Page::render_model_field(); }
+ public static function render_model_field(): void {
+ PSA_Admin_Page::render_model_field(); }
/** @see PSA_Admin_Page::render_validation_model_field() */
- public static function render_validation_model_field(): void { PSA_Admin_Page::render_validation_model_field(); }
+ public static function render_validation_model_field(): void {
+ PSA_Admin_Page::render_validation_model_field(); }
/** @see PSA_Admin_Page::render_publish_field() */
- public static function render_publish_field(): void { PSA_Admin_Page::render_publish_field(); }
+ public static function render_publish_field(): void {
+ PSA_Admin_Page::render_publish_field(); }
/** @see PSA_Admin_Page::render_pubchem_field() */
- public static function render_pubchem_field(): void { PSA_Admin_Page::render_pubchem_field(); }
+ public static function render_pubchem_field(): void {
+ PSA_Admin_Page::render_pubchem_field(); }
/** @see PSA_Admin_Page::render_budget_field() */
- public static function render_budget_field(): void { PSA_Admin_Page::render_budget_field(); }
+ public static function render_budget_field(): void {
+ PSA_Admin_Page::render_budget_field(); }
/** @see PSA_Admin_Page::render_settings_page() */
- public static function render_settings_page(): void { PSA_Admin_Page::render_settings_page(); }
+ public static function render_settings_page(): void {
+ PSA_Admin_Page::render_settings_page(); }
}
diff --git a/includes/class-psa-ai-generator.php b/includes/class-psa-ai-generator.php
index 7e683c9..922f723 100755
--- a/includes/class-psa-ai-generator.php
+++ b/includes/class-psa-ai-generator.php
@@ -35,7 +35,11 @@ class PSA_AI_Generator {
*/
public static function validate_peptide_name( string $name ) {
if ( ! self::validate_peptide_input( $name ) ) {
- return array( 'is_valid' => false, 'canonical_name' => $name, 'reason' => 'Invalid characters in peptide name.' );
+ return array(
+ 'is_valid' => false,
+ 'canonical_name' => $name,
+ 'reason' => 'Invalid characters in peptide name.',
+ );
}
$options = self::get_settings();
@@ -70,7 +74,11 @@ class PSA_AI_Generator {
$data = PSA_OpenRouter::parse_response( $response );
if ( is_wp_error( $data ) ) {
- return array( 'is_valid' => false, 'canonical_name' => $name, 'reason' => 'Could not verify this peptide name.' );
+ return array(
+ 'is_valid' => false,
+ 'canonical_name' => $name,
+ 'reason' => 'Could not verify this peptide name.',
+ );
}
$result = array(
@@ -136,12 +144,15 @@ class PSA_AI_Generator {
}
$post_status = ( 'publish' === $options['auto_publish'] ) ? 'publish' : 'draft';
- $update_result = wp_update_post( array(
- 'ID' => $post_id,
- 'post_title' => sanitize_text_field( $result['name'] ?? $peptide_name ),
- 'post_content' => wp_kses_post( $post_content ),
- 'post_status' => $post_status,
- ), true );
+ $update_result = wp_update_post(
+ array(
+ 'ID' => $post_id,
+ 'post_title' => sanitize_text_field( $result['name'] ?? $peptide_name ),
+ 'post_content' => wp_kses_post( $post_content ),
+ 'post_status' => $post_status,
+ ),
+ true
+ );
if ( is_wp_error( $update_result ) ) {
error_log( 'PSA: wp_update_post FAILED for post ' . $post_id . ': ' . $update_result->get_error_message() );
@@ -214,8 +225,14 @@ class PSA_AI_Generator {
$gen_cost = PSA_Cost_Tracker::estimate_cost( $generation_model, $gen_tokens, PSA_Config::GENERATION_MAX_TOKENS );
return array(
- 'validation' => array( 'tokens' => $val_tokens + PSA_Config::VALIDATION_MAX_TOKENS, 'estimated_cost_usd' => $val_cost ),
- 'generation' => array( 'tokens' => $gen_tokens + PSA_Config::GENERATION_MAX_TOKENS, 'estimated_cost_usd' => $gen_cost ),
+ 'validation' => array(
+ 'tokens' => $val_tokens + PSA_Config::VALIDATION_MAX_TOKENS,
+ 'estimated_cost_usd' => $val_cost,
+ ),
+ 'generation' => array(
+ 'tokens' => $gen_tokens + PSA_Config::GENERATION_MAX_TOKENS,
+ 'estimated_cost_usd' => $gen_cost,
+ ),
'total_estimated_cost_usd' => $val_cost + $gen_cost,
);
}
@@ -228,7 +245,13 @@ class PSA_AI_Generator {
* @return array
*/
private static function get_settings(): array {
- $defaults = array( 'api_key' => '', 'ai_model' => '', 'validation_model' => '', 'auto_publish' => 'draft', 'use_pubchem' => '1' );
+ $defaults = array(
+ 'api_key' => '',
+ 'ai_model' => '',
+ 'validation_model' => '',
+ 'auto_publish' => 'draft',
+ 'use_pubchem' => '1',
+ );
$settings = wp_parse_args( get_option( 'psa_settings', array() ), $defaults );
if ( ! empty( $settings['api_key'] ) && ! ( defined( 'PSA_OPENROUTER_KEY' ) && PSA_OPENROUTER_KEY ) ) {
@@ -269,14 +292,18 @@ class PSA_AI_Generator {
// ── Backward-compatible proxies ─────────────────────────────────────
/** @see PSA_AI_Content::build_validation_prompt() */
- public static function build_validation_prompt( string $name ): string { return PSA_AI_Content::build_validation_prompt( $name ); }
+ public static function build_validation_prompt( string $name ): string {
+ return PSA_AI_Content::build_validation_prompt( $name ); }
/** @see PSA_AI_Content::build_generation_prompt() */
- public static function build_generation_prompt( string $peptide_name ): string { return PSA_AI_Content::build_generation_prompt( $peptide_name ); }
+ public static function build_generation_prompt( string $peptide_name ): string {
+ return PSA_AI_Content::build_generation_prompt( $peptide_name ); }
/** @see PSA_AI_Content::save_peptide_meta() */
- public static function save_peptide_meta( int $post_id, array $ai_data, ?array $pubchem_data ): void { PSA_AI_Content::save_peptide_meta( $post_id, $ai_data, $pubchem_data ); }
+ public static function save_peptide_meta( int $post_id, array $ai_data, ?array $pubchem_data ): void {
+ PSA_AI_Content::save_peptide_meta( $post_id, $ai_data, $pubchem_data ); }
/** @see PSA_AI_Content::assign_category_term() */
- public static function assign_category_term( int $post_id, array $ai_data ): void { PSA_AI_Content::assign_category_term( $post_id, $ai_data ); }
+ public static function assign_category_term( int $post_id, array $ai_data ): void {
+ PSA_AI_Content::assign_category_term( $post_id, $ai_data ); }
}
diff --git a/includes/class-psa-batch-enrichment.php b/includes/class-psa-batch-enrichment.php
index 32c4189..7df932f 100755
--- a/includes/class-psa-batch-enrichment.php
+++ b/includes/class-psa-batch-enrichment.php
@@ -106,7 +106,7 @@ class PSA_Batch_Enrichment {
PSA_AI_Generator::background_generate( $post_id, $peptide_name );
// Check outcome: did generation succeed?
- $error = get_post_meta( $post_id, 'psa_generation_error', true );
+ $error = get_post_meta( $post_id, 'psa_generation_error', true );
$refreshed_post = get_post( $post_id );
// If still in draft (generation failed or auto_publish is 'draft'), force republish.
diff --git a/includes/class-psa-config.php b/includes/class-psa-config.php
index 1fd1ec1..c22f19b 100755
--- a/includes/class-psa-config.php
+++ b/includes/class-psa-config.php
@@ -25,23 +25,23 @@ class PSA_Config {
const AJAX_RATE_LIMIT = 10;
// Daily generation cap
- const DAILY_GENERATION_CAP = 50;
+ const DAILY_GENERATION_CAP = 50;
// Generation timing
const PENDING_TIMEOUT = 300; // seconds (5 minutes)
const MAX_GENERATION_RETRIES = 3;
// AI token limits
- const VALIDATION_MAX_TOKENS = 300;
- const GENERATION_MAX_TOKENS = 4096;
+ const VALIDATION_MAX_TOKENS = 300;
+ const GENERATION_MAX_TOKENS = 4096;
// Cache TTL
- const VALIDATION_CACHE_TTL = null; // Set to DAY_IN_SECONDS at runtime
- const PUBCHEM_CACHE_TTL = null; // Set to 7 * DAY_IN_SECONDS at runtime
+ const VALIDATION_CACHE_TTL = null; // Set to DAY_IN_SECONDS at runtime
+ const PUBCHEM_CACHE_TTL = null; // Set to 7 * DAY_IN_SECONDS at runtime
// API retry settings
- const API_RETRY_MAX = 3;
- const API_RETRY_BASE_DELAY = 5; // seconds
+ const API_RETRY_MAX = 3;
+ const API_RETRY_BASE_DELAY = 5; // seconds
// Cost tracking and budget
const DEFAULT_MONTHLY_BUDGET = 0; // 0 = unlimited
diff --git a/includes/class-psa-cost-reporter.php b/includes/class-psa-cost-reporter.php
index 148eab1..88f50bc 100644
--- a/includes/class-psa-cost-reporter.php
+++ b/includes/class-psa-cost-reporter.php
@@ -29,7 +29,7 @@ class PSA_Cost_Reporter {
public static function get_monthly_spend( ?int $year = null, ?int $month = null ): float {
global $wpdb;
list( $start, $end ) = self::month_range( $year, $month );
- $table = $wpdb->prefix . 'psa_api_logs';
+ $table = $wpdb->prefix . 'psa_api_logs';
// phpcs:ignore WordPress.DB.DirectDatabaseQuery
$result = $wpdb->get_var(
@@ -53,7 +53,7 @@ class PSA_Cost_Reporter {
public static function get_monthly_tokens( ?int $year = null, ?int $month = null ): int {
global $wpdb;
list( $start, $end ) = self::month_range( $year, $month );
- $table = $wpdb->prefix . 'psa_api_logs';
+ $table = $wpdb->prefix . 'psa_api_logs';
// phpcs:ignore WordPress.DB.DirectDatabaseQuery
$result = $wpdb->get_var(
@@ -80,7 +80,7 @@ class PSA_Cost_Reporter {
public static function get_monthly_estimated_count( ?int $year = null, ?int $month = null ): int {
global $wpdb;
list( $start, $end ) = self::month_range( $year, $month );
- $table = $wpdb->prefix . 'psa_api_logs';
+ $table = $wpdb->prefix . 'psa_api_logs';
// phpcs:ignore WordPress.DB.DirectDatabaseQuery
$result = $wpdb->get_var(
diff --git a/includes/class-psa-cost-tracker.php b/includes/class-psa-cost-tracker.php
index 6eec5d9..7470db7 100755
--- a/includes/class-psa-cost-tracker.php
+++ b/includes/class-psa-cost-tracker.php
@@ -158,14 +158,18 @@ class PSA_Cost_Tracker {
// ── Backward-compatible proxies (reporting moved to PSA_Cost_Reporter) ──
/** @see PSA_Cost_Reporter::get_monthly_spend() */
- public static function get_monthly_spend( ?int $year = null, ?int $month = null ): float { return PSA_Cost_Reporter::get_monthly_spend( $year, $month ); }
+ public static function get_monthly_spend( ?int $year = null, ?int $month = null ): float {
+ return PSA_Cost_Reporter::get_monthly_spend( $year, $month ); }
/** @see PSA_Cost_Reporter::get_monthly_tokens() */
- public static function get_monthly_tokens( ?int $year = null, ?int $month = null ): int { return PSA_Cost_Reporter::get_monthly_tokens( $year, $month ); }
+ public static function get_monthly_tokens( ?int $year = null, ?int $month = null ): int {
+ return PSA_Cost_Reporter::get_monthly_tokens( $year, $month ); }
/** @see PSA_Cost_Reporter::get_monthly_estimated_count() */
- public static function get_monthly_estimated_count( ?int $year = null, ?int $month = null ): int { return PSA_Cost_Reporter::get_monthly_estimated_count( $year, $month ); }
+ public static function get_monthly_estimated_count( ?int $year = null, ?int $month = null ): int {
+ return PSA_Cost_Reporter::get_monthly_estimated_count( $year, $month ); }
/** @see PSA_Cost_Reporter::get_recent_logs() */
- public static function get_recent_logs( int $limit = 20 ): array { return PSA_Cost_Reporter::get_recent_logs( $limit ); }
+ public static function get_recent_logs( int $limit = 20 ): array {
+ return PSA_Cost_Reporter::get_recent_logs( $limit ); }
}
diff --git a/includes/class-psa-directory-api.php b/includes/class-psa-directory-api.php
index 1abbad7..3d47b76 100644
--- a/includes/class-psa-directory-api.php
+++ b/includes/class-psa-directory-api.php
@@ -23,18 +23,45 @@ class PSA_Directory_API {
* Register the /v1/compounds endpoint. Public (no auth) — rate limiting at server/CDN level.
*/
public static function register_rest_routes(): void {
- register_rest_route( 'peptide-search-ai/v1', '/compounds', array(
- 'methods' => 'GET',
- 'callback' => array( __CLASS__, 'rest_compounds' ),
- 'permission_callback' => '__return_true',
- 'args' => array(
- 'search' => array( 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => '' ),
- 'category' => array( 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => '' ),
- 'fields' => array( 'type' => 'string', 'enum' => array( 'basic', 'full' ), 'default' => 'full' ),
- 'page' => array( 'type' => 'integer', 'default' => 1, 'minimum' => 1, 'sanitize_callback' => 'absint' ),
- 'per_page' => array( 'type' => 'integer', 'default' => PSA_Directory::PER_PAGE_DEFAULT, 'minimum' => 1, 'maximum' => PSA_Directory::PER_PAGE_MAX, 'sanitize_callback' => 'absint' ),
- ),
- ) );
+ register_rest_route(
+ 'peptide-search-ai/v1',
+ '/compounds',
+ array(
+ 'methods' => 'GET',
+ 'callback' => array( __CLASS__, 'rest_compounds' ),
+ 'permission_callback' => '__return_true',
+ 'args' => array(
+ 'search' => array(
+ 'type' => 'string',
+ 'sanitize_callback' => 'sanitize_text_field',
+ 'default' => '',
+ ),
+ 'category' => array(
+ 'type' => 'string',
+ 'sanitize_callback' => 'sanitize_text_field',
+ 'default' => '',
+ ),
+ 'fields' => array(
+ 'type' => 'string',
+ 'enum' => array( 'basic', 'full' ),
+ 'default' => 'full',
+ ),
+ 'page' => array(
+ 'type' => 'integer',
+ 'default' => 1,
+ 'minimum' => 1,
+ 'sanitize_callback' => 'absint',
+ ),
+ 'per_page' => array(
+ 'type' => 'integer',
+ 'default' => PSA_Directory::PER_PAGE_DEFAULT,
+ 'minimum' => 1,
+ 'maximum' => PSA_Directory::PER_PAGE_MAX,
+ 'sanitize_callback' => 'absint',
+ ),
+ ),
+ )
+ );
}
/**
@@ -65,11 +92,13 @@ class PSA_Directory_API {
}
if ( ! empty( $category ) ) {
- $query_args['tax_query'] = array( array(
- 'taxonomy' => 'peptide_category',
- 'field' => 'slug',
- 'terms' => $category,
- ) );
+ $query_args['tax_query'] = array(
+ array(
+ 'taxonomy' => 'peptide_category',
+ 'field' => 'slug',
+ 'terms' => $category,
+ ),
+ );
}
$query = new WP_Query( $query_args );
@@ -83,13 +112,16 @@ class PSA_Directory_API {
$compounds[] = self::format_compound( $post, $fields );
}
- $response = new WP_REST_Response( array(
- 'compounds' => $compounds,
- 'total' => (int) $query->found_posts,
- 'total_pages' => (int) $query->max_num_pages,
- 'page' => $page,
- 'per_page' => $per_page,
- ), 200 );
+ $response = new WP_REST_Response(
+ array(
+ 'compounds' => $compounds,
+ 'total' => (int) $query->found_posts,
+ 'total_pages' => (int) $query->max_num_pages,
+ 'page' => $page,
+ 'per_page' => $per_page,
+ ),
+ 200
+ );
$response->header( 'X-WP-Total', (string) $query->found_posts );
$response->header( 'X-WP-TotalPages', (string) $query->max_num_pages );
@@ -111,7 +143,10 @@ class PSA_Directory_API {
$categories = array();
if ( ! is_wp_error( $terms ) ) {
foreach ( $terms as $term ) {
- $categories[] = array( 'slug' => $term->slug, 'name' => $term->name );
+ $categories[] = array(
+ 'slug' => $term->slug,
+ 'name' => $term->name,
+ );
}
}
@@ -132,27 +167,30 @@ class PSA_Directory_API {
return $basic;
}
- $full = array_merge( $basic, array(
- 'excerpt' => wp_trim_words( $post->post_content, 30 ),
- 'description' => wp_trim_words( $post->post_content, 80 ),
- 'sequence' => get_post_meta( $id, 'psa_sequence', true ),
- 'molecular_weight' => get_post_meta( $id, 'psa_molecular_weight', true ),
- 'molecular_formula' => get_post_meta( $id, 'psa_molecular_formula', true ),
- 'aliases' => get_post_meta( $id, 'psa_aliases', true ),
- 'mechanism' => get_post_meta( $id, 'psa_mechanism', true ),
- 'research_apps' => get_post_meta( $id, 'psa_research_apps', true ),
- 'safety_profile' => get_post_meta( $id, 'psa_safety_profile', true ),
- 'dosage_info' => get_post_meta( $id, 'psa_dosage_info', true ),
- 'references' => get_post_meta( $id, 'psa_references', true ),
- 'pubchem_cid' => get_post_meta( $id, 'psa_pubchem_cid', true ),
- 'solubility' => get_post_meta( $id, 'psa_solubility', true ),
- 'vial_size_mg' => get_post_meta( $id, 'psa_vial_size_mg', true ),
- 'storage_lyophilized' => get_post_meta( $id, 'psa_storage_lyophilized', true ),
- 'storage_reconstituted' => get_post_meta( $id, 'psa_storage_reconstituted', true ),
- 'typical_dose_mcg' => get_post_meta( $id, 'psa_typical_dose_mcg', true ),
- 'cycle_parameters' => get_post_meta( $id, 'psa_cycle_parameters', true ),
- 'amino_acid_count' => get_post_meta( $id, 'psa_amino_acid_count', true ),
- ) );
+ $full = array_merge(
+ $basic,
+ array(
+ 'excerpt' => wp_trim_words( $post->post_content, 30 ),
+ 'description' => wp_trim_words( $post->post_content, 80 ),
+ 'sequence' => get_post_meta( $id, 'psa_sequence', true ),
+ 'molecular_weight' => get_post_meta( $id, 'psa_molecular_weight', true ),
+ 'molecular_formula' => get_post_meta( $id, 'psa_molecular_formula', true ),
+ 'aliases' => get_post_meta( $id, 'psa_aliases', true ),
+ 'mechanism' => get_post_meta( $id, 'psa_mechanism', true ),
+ 'research_apps' => get_post_meta( $id, 'psa_research_apps', true ),
+ 'safety_profile' => get_post_meta( $id, 'psa_safety_profile', true ),
+ 'dosage_info' => get_post_meta( $id, 'psa_dosage_info', true ),
+ 'references' => get_post_meta( $id, 'psa_references', true ),
+ 'pubchem_cid' => get_post_meta( $id, 'psa_pubchem_cid', true ),
+ 'solubility' => get_post_meta( $id, 'psa_solubility', true ),
+ 'vial_size_mg' => get_post_meta( $id, 'psa_vial_size_mg', true ),
+ 'storage_lyophilized' => get_post_meta( $id, 'psa_storage_lyophilized', true ),
+ 'storage_reconstituted' => get_post_meta( $id, 'psa_storage_reconstituted', true ),
+ 'typical_dose_mcg' => get_post_meta( $id, 'psa_typical_dose_mcg', true ),
+ 'cycle_parameters' => get_post_meta( $id, 'psa_cycle_parameters', true ),
+ 'amino_acid_count' => get_post_meta( $id, 'psa_amino_acid_count', true ),
+ )
+ );
return apply_filters( 'psa_rest_compound_data', $full, $id );
}
diff --git a/includes/class-psa-directory.php b/includes/class-psa-directory.php
index 3a57d8c..b5f309e 100755
--- a/includes/class-psa-directory.php
+++ b/includes/class-psa-directory.php
@@ -38,57 +38,66 @@ class PSA_Directory {
* @return string HTML output.
*/
public static function render_shortcode( $atts ): string {
- $terms = get_terms( array(
- 'taxonomy' => 'peptide_category',
- 'hide_empty' => false,
- 'orderby' => 'name',
- 'order' => 'ASC',
- ) );
+ $terms = get_terms(
+ array(
+ 'taxonomy' => 'peptide_category',
+ 'hide_empty' => false,
+ 'orderby' => 'name',
+ 'order' => 'ASC',
+ )
+ );
$categories = array();
if ( ! is_wp_error( $terms ) ) {
foreach ( $terms as $term ) {
- $categories[] = array( 'slug' => $term->slug, 'name' => $term->name );
+ $categories[] = array(
+ 'slug' => $term->slug,
+ 'name' => $term->name,
+ );
}
}
- wp_localize_script( 'psa-directory', 'psaDirectory', array(
- 'restUrl' => esc_url_raw( rest_url( 'peptide-search-ai/v1/compounds' ) ),
- 'nonce' => wp_create_nonce( 'wp_rest' ),
- 'categories' => $categories,
- 'perPage' => self::PER_PAGE_DEFAULT,
- 'i18n' => array(
- 'title' => __( 'Peptide Directory', 'peptide-search-ai' ),
- 'subtitle' => __( 'Browse reagents with detailed research parameters.', 'peptide-search-ai' ),
- 'searchPlaceholder' => __( 'Search peptides...', 'peptide-search-ai' ),
- 'showAll' => __( 'Show All', 'peptide-search-ai' ),
- 'loadMore' => __( 'Load More', 'peptide-search-ai' ),
- 'loading' => __( 'Loading...', 'peptide-search-ai' ),
- 'noResults' => __( 'No peptides found matching your criteria.', 'peptide-search-ai' ),
- 'viewDetails' => __( 'View Research Details', 'peptide-search-ai' ),
- 'viewFullPage' => __( 'View Full Page', 'peptide-search-ai' ),
- 'close' => __( 'Close', 'peptide-search-ai' ),
- 'halfLife' => __( 'Half-Life', 'peptide-search-ai' ),
- 'stability' => __( 'Stability', 'peptide-search-ai' ),
- 'solubility' => __( 'Solubility', 'peptide-search-ai' ),
- 'vialSize' => __( 'Vial Size', 'peptide-search-ai' ),
- 'storageLyo' => __( 'Storage (Lyophilized)', 'peptide-search-ai' ),
- 'storageRecon' => __( 'Storage (Reconstituted)', 'peptide-search-ai' ),
- 'molecularWeight' => __( 'Molecular Weight', 'peptide-search-ai' ),
- 'formula' => __( 'Formula', 'peptide-search-ai' ),
- 'typicalDose' => __( 'Typical Dose', 'peptide-search-ai' ),
- 'cycleParams' => __( 'Cycle Parameters', 'peptide-search-ai' ),
- 'sequence' => __( 'Sequence', 'peptide-search-ai' ),
- 'singleReagents' => __( 'Single Reagents', 'peptide-search-ai' ),
- 'protocolModels' => __( 'Protocol Models', 'peptide-search-ai' ),
- 'comingSoon' => __( 'Coming Soon', 'peptide-search-ai' ),
- 'researchParams' => __( 'Research Parameters', 'peptide-search-ai' ),
- 'communityObs' => __( 'Community Observations', 'peptide-search-ai' ),
- 'pubchemLink' => __( 'View on PubChem', 'peptide-search-ai' ),
- 'copySequence' => __( 'Copy', 'peptide-search-ai' ),
- 'copied' => __( 'Copied!', 'peptide-search-ai' ),
- ),
- ) );
+ wp_localize_script(
+ 'psa-directory',
+ 'psaDirectory',
+ array(
+ 'restUrl' => esc_url_raw( rest_url( 'peptide-search-ai/v1/compounds' ) ),
+ 'nonce' => wp_create_nonce( 'wp_rest' ),
+ 'categories' => $categories,
+ 'perPage' => self::PER_PAGE_DEFAULT,
+ 'i18n' => array(
+ 'title' => __( 'Peptide Directory', 'peptide-search-ai' ),
+ 'subtitle' => __( 'Browse reagents with detailed research parameters.', 'peptide-search-ai' ),
+ 'searchPlaceholder' => __( 'Search peptides...', 'peptide-search-ai' ),
+ 'showAll' => __( 'Show All', 'peptide-search-ai' ),
+ 'loadMore' => __( 'Load More', 'peptide-search-ai' ),
+ 'loading' => __( 'Loading...', 'peptide-search-ai' ),
+ 'noResults' => __( 'No peptides found matching your criteria.', 'peptide-search-ai' ),
+ 'viewDetails' => __( 'View Research Details', 'peptide-search-ai' ),
+ 'viewFullPage' => __( 'View Full Page', 'peptide-search-ai' ),
+ 'close' => __( 'Close', 'peptide-search-ai' ),
+ 'halfLife' => __( 'Half-Life', 'peptide-search-ai' ),
+ 'stability' => __( 'Stability', 'peptide-search-ai' ),
+ 'solubility' => __( 'Solubility', 'peptide-search-ai' ),
+ 'vialSize' => __( 'Vial Size', 'peptide-search-ai' ),
+ 'storageLyo' => __( 'Storage (Lyophilized)', 'peptide-search-ai' ),
+ 'storageRecon' => __( 'Storage (Reconstituted)', 'peptide-search-ai' ),
+ 'molecularWeight' => __( 'Molecular Weight', 'peptide-search-ai' ),
+ 'formula' => __( 'Formula', 'peptide-search-ai' ),
+ 'typicalDose' => __( 'Typical Dose', 'peptide-search-ai' ),
+ 'cycleParams' => __( 'Cycle Parameters', 'peptide-search-ai' ),
+ 'sequence' => __( 'Sequence', 'peptide-search-ai' ),
+ 'singleReagents' => __( 'Single Reagents', 'peptide-search-ai' ),
+ 'protocolModels' => __( 'Protocol Models', 'peptide-search-ai' ),
+ 'comingSoon' => __( 'Coming Soon', 'peptide-search-ai' ),
+ 'researchParams' => __( 'Research Parameters', 'peptide-search-ai' ),
+ 'communityObs' => __( 'Community Observations', 'peptide-search-ai' ),
+ 'pubchemLink' => __( 'View on PubChem', 'peptide-search-ai' ),
+ 'copySequence' => __( 'Copy', 'peptide-search-ai' ),
+ 'copied' => __( 'Copied!', 'peptide-search-ai' ),
+ ),
+ )
+ );
ob_start();
?>
@@ -104,11 +113,14 @@ class PSA_Directory {
// ── Backward-compatible proxies (REST moved to PSA_Directory_API) ───
/** @see PSA_Directory_API::register_rest_routes() */
- public static function register_rest_routes(): void { PSA_Directory_API::register_rest_routes(); }
+ public static function register_rest_routes(): void {
+ PSA_Directory_API::register_rest_routes(); }
/** @see PSA_Directory_API::rest_compounds() */
- public static function rest_compounds( $request ) { return PSA_Directory_API::rest_compounds( $request ); }
+ public static function rest_compounds( $request ) {
+ return PSA_Directory_API::rest_compounds( $request ); }
/** @see PSA_Directory_API::format_compound() */
- public static function format_compound( $post, string $fields = 'full' ): array { return PSA_Directory_API::format_compound( $post, $fields ); }
+ public static function format_compound( $post, string $fields = 'full' ): array {
+ return PSA_Directory_API::format_compound( $post, $fields ); }
}
diff --git a/includes/class-psa-encryption.php b/includes/class-psa-encryption.php
index c21b2a7..a407fae 100755
--- a/includes/class-psa-encryption.php
+++ b/includes/class-psa-encryption.php
@@ -79,7 +79,7 @@ class PSA_Encryption {
}
// First 16 bytes are the IV.
- $iv = substr( $data, 0, 16 );
+ $iv = substr( $data, 0, 16 );
$encrypted_data = substr( $data, 16 );
// Decrypt.
diff --git a/includes/class-psa-kb-builder.php b/includes/class-psa-kb-builder.php
index e23f4c3..baf323e 100755
--- a/includes/class-psa-kb-builder.php
+++ b/includes/class-psa-kb-builder.php
@@ -47,7 +47,7 @@ class PSA_KB_Builder {
return;
}
- $title = sanitize_text_field( $ai_data['name'] ?? $peptide_name );
+ $title = sanitize_text_field( $ai_data['name'] ?? $peptide_name );
$existing = get_posts(
array(
'post_type' => 'epkb_post_type_1',
@@ -124,10 +124,10 @@ class PSA_KB_Builder {
// Research & Potential Benefits (with h3 subheadings).
if ( ! empty( $ai_data['research_benefits'] ) || ! empty( $ai_data['research_applications'] ) ) {
- $c .= '
Research & Potential Benefits
' . "\n";
- $c .= '
The following potential benefits are based on animal studies and preclinical research. Human clinical trial data is extremely limited.
' . "\n";
+ $c .= '
Research & Potential Benefits
' . "\n";
+ $c .= '
The following potential benefits are based on animal studies and preclinical research. Human clinical trial data is extremely limited.
' . "\n";
$research = $ai_data['research_benefits'] ?? $ai_data['research_applications'] ?? '';
- $c .= self::research_with_subheadings( $research );
+ $c .= self::research_with_subheadings( $research );
}
// Administration & Dosing.
diff --git a/includes/class-psa-openrouter.php b/includes/class-psa-openrouter.php
index 5c9c6bc..312a479 100755
--- a/includes/class-psa-openrouter.php
+++ b/includes/class-psa-openrouter.php
@@ -90,15 +90,15 @@ class PSA_OpenRouter {
array(
'timeout' => 120,
'headers' => array(
- 'Content-Type' => 'application/json',
- 'Authorization' => 'Bearer ' . $api_key,
- 'HTTP-Referer' => $site_url,
- 'X-Title' => $site_name,
+ 'Content-Type' => 'application/json',
+ 'Authorization' => 'Bearer ' . $api_key,
+ 'HTTP-Referer' => $site_url,
+ 'X-Title' => $site_name,
),
- 'body' => wp_json_encode(
+ 'body' => wp_json_encode(
array(
- 'model' => $model,
- 'messages' => array(
+ 'model' => $model,
+ 'messages' => array(
array(
'role' => 'system',
'content' => 'You are a scientific database assistant. Return only valid JSON.',
@@ -108,8 +108,8 @@ class PSA_OpenRouter {
'content' => $prompt,
),
),
- 'max_tokens' => $max_tokens,
- 'temperature' => 0.3,
+ 'max_tokens' => $max_tokens,
+ 'temperature' => 0.3,
)
),
)
@@ -147,10 +147,10 @@ class PSA_OpenRouter {
}
// Log API call with token usage.
- $response_text = $body['choices'][0]['message']['content'];
- $prompt_tokens = (int) ( $body['usage']['prompt_tokens'] ?? 0 );
+ $response_text = $body['choices'][0]['message']['content'];
+ $prompt_tokens = (int) ( $body['usage']['prompt_tokens'] ?? 0 );
$completion_tokens = (int) ( $body['usage']['completion_tokens'] ?? 0 );
- $token_source = 'api';
+ $token_source = 'api';
// Diagnostic: log the raw usage structure once per model so we can verify
// whether the provider returns token counts. Remove after confirming.
@@ -172,14 +172,14 @@ class PSA_OpenRouter {
PSA_Cost_Tracker::log_api_call(
array(
- 'provider' => 'openrouter',
- 'model' => $model,
- 'prompt_tokens' => $prompt_tokens,
- 'completion_tokens' => $completion_tokens,
- 'request_type' => $request_type,
- 'peptide_name' => $peptide_name,
- 'success' => true,
- 'token_source' => $token_source,
+ 'provider' => 'openrouter',
+ 'model' => $model,
+ 'prompt_tokens' => $prompt_tokens,
+ 'completion_tokens' => $completion_tokens,
+ 'request_type' => $request_type,
+ 'peptide_name' => $peptide_name,
+ 'success' => true,
+ 'token_source' => $token_source,
)
);
diff --git a/includes/class-psa-post-type-meta.php b/includes/class-psa-post-type-meta.php
index 7f21480..530be31 100644
--- a/includes/class-psa-post-type-meta.php
+++ b/includes/class-psa-post-type-meta.php
@@ -47,8 +47,12 @@ class PSA_Post_Type_Meta {
wp_nonce_field( 'psa_save_meta', 'psa_meta_nonce' );
$textarea_fields = array(
- 'psa_sequence', 'psa_mechanism', 'psa_research_apps',
- 'psa_safety_profile', 'psa_dosage_info', 'psa_references',
+ 'psa_sequence',
+ 'psa_mechanism',
+ 'psa_research_apps',
+ 'psa_safety_profile',
+ 'psa_dosage_info',
+ 'psa_references',
);
echo '