fix: resolve PHPCS errors and PHPUnit test failures for CI
Move declare(strict_types=1) after file-level docblock in all 12 class files to satisfy WordPress Coding Standards docblock placement rule. Fix multi-line function call formatting in class-psa-admin.php. Align array double arrows and equals signs. Fix escaped backticks in AIGeneratorTest heredoc that broke markdown fence stripping tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
declare( strict_types=1 );
|
|
||||||
/**
|
/**
|
||||||
* Admin settings page for Peptide Search AI.
|
* Admin settings page for Peptide Search AI.
|
||||||
*
|
*
|
||||||
@@ -12,6 +11,7 @@ declare( strict_types=1 );
|
|||||||
* @see includes/class-psa-cost-tracker.php
|
* @see includes/class-psa-cost-tracker.php
|
||||||
* @see includes/class-psa-post-type.php
|
* @see includes/class-psa-post-type.php
|
||||||
*/
|
*/
|
||||||
|
declare( strict_types=1 );
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
@@ -74,21 +74,21 @@ class PSA_Admin {
|
|||||||
$api_key_value = '';
|
$api_key_value = '';
|
||||||
|
|
||||||
if ( ! empty( $api_key_input ) && '••••••••' !== $api_key_input ) {
|
if ( ! empty( $api_key_input ) && '••••••••' !== $api_key_input ) {
|
||||||
$sanitized = sanitize_text_field( $api_key_input );
|
$sanitized = sanitize_text_field( $api_key_input );
|
||||||
$encrypted = PSA_Encryption::encrypt( $sanitized );
|
$encrypted = PSA_Encryption::encrypt( $sanitized );
|
||||||
$api_key_value = ( false !== $encrypted ) ? $encrypted : '';
|
$api_key_value = ( false !== $encrypted ) ? $encrypted : '';
|
||||||
} else {
|
} else {
|
||||||
$existing = self::get_setting( 'api_key', '' );
|
$existing = self::get_setting( 'api_key', '' );
|
||||||
$api_key_value = $existing;
|
$api_key_value = $existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'api_key' => $api_key_value,
|
'api_key' => $api_key_value,
|
||||||
'ai_model' => sanitize_text_field( $input['ai_model'] ?? '' ),
|
'ai_model' => sanitize_text_field( $input['ai_model'] ?? '' ),
|
||||||
'validation_model' => sanitize_text_field( $input['validation_model'] ?? '' ),
|
'validation_model' => sanitize_text_field( $input['validation_model'] ?? '' ),
|
||||||
'auto_publish' => sanitize_text_field( $input['auto_publish'] ?? 'draft' ),
|
'auto_publish' => sanitize_text_field( $input['auto_publish'] ?? 'draft' ),
|
||||||
'use_pubchem' => ! empty( $input['use_pubchem'] ) ? '1' : '0',
|
'use_pubchem' => ! empty( $input['use_pubchem'] ) ? '1' : '0',
|
||||||
'monthly_budget' => max( 0, floatval( $input['monthly_budget'] ?? PSA_Config::DEFAULT_MONTHLY_BUDGET ) ),
|
'monthly_budget' => max( 0, floatval( $input['monthly_budget'] ?? PSA_Config::DEFAULT_MONTHLY_BUDGET ) ),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,20 +106,28 @@ class PSA_Admin {
|
|||||||
|
|
||||||
if ( 'migrate_categories' === $action && wp_verify_nonce( $nonce, 'psa_migrate_categories' ) ) {
|
if ( 'migrate_categories' === $action && wp_verify_nonce( $nonce, 'psa_migrate_categories' ) ) {
|
||||||
self::run_category_migration();
|
self::run_category_migration();
|
||||||
add_action( 'admin_notices', function () {
|
add_action(
|
||||||
echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Category migration completed.', 'peptide-search-ai' ) . '</p></div>';
|
'admin_notices',
|
||||||
} );
|
function () {
|
||||||
|
echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Category migration completed.', 'peptide-search-ai' ) . '</p></div>';
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( 'reenrich' === $action && wp_verify_nonce( $nonce, 'psa_reenrich' ) ) {
|
if ( 'reenrich' === $action && wp_verify_nonce( $nonce, 'psa_reenrich' ) ) {
|
||||||
$queued = self::queue_reenrichment();
|
$queued = self::queue_reenrichment();
|
||||||
add_action( 'admin_notices', function () use ( $queued ) {
|
add_action(
|
||||||
echo '<div class="notice notice-success is-dismissible"><p>' . esc_html( sprintf(
|
'admin_notices',
|
||||||
/* translators: %d = number of peptides queued */
|
function () use ( $queued ) {
|
||||||
__( '%d peptides queued for re-enrichment.', 'peptide-search-ai' ),
|
echo '<div class="notice notice-success is-dismissible"><p>' . esc_html(
|
||||||
$queued
|
sprintf(
|
||||||
) ) . '</p></div>';
|
/* translators: %d = number of peptides queued */
|
||||||
} );
|
__( '%d peptides queued for re-enrichment.', 'peptide-search-ai' ),
|
||||||
|
$queued
|
||||||
|
)
|
||||||
|
) . '</p></div>';
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
declare( strict_types=1 );
|
|
||||||
/**
|
/**
|
||||||
* Handles AI content generation for new peptide entries.
|
* Handles AI content generation for new peptide entries.
|
||||||
*
|
*
|
||||||
@@ -13,6 +12,7 @@ declare( strict_types=1 );
|
|||||||
* @see includes/class-psa-pubchem.php
|
* @see includes/class-psa-pubchem.php
|
||||||
* @see includes/class-psa-post-type.php
|
* @see includes/class-psa-post-type.php
|
||||||
*/
|
*/
|
||||||
|
declare( strict_types=1 );
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
declare( strict_types=1 );
|
|
||||||
/**
|
/**
|
||||||
* Configuration constants for Peptide Search AI.
|
* Configuration constants for Peptide Search AI.
|
||||||
*
|
*
|
||||||
@@ -9,6 +8,7 @@ declare( strict_types=1 );
|
|||||||
*
|
*
|
||||||
* @package PeptideSearchAI
|
* @package PeptideSearchAI
|
||||||
*/
|
*/
|
||||||
|
declare( strict_types=1 );
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
declare( strict_types=1 );
|
|
||||||
/**
|
/**
|
||||||
* Tracks API usage costs and enforces monthly budget limits.
|
* Tracks API usage costs and enforces monthly budget limits.
|
||||||
*
|
*
|
||||||
@@ -10,6 +9,7 @@ declare( strict_types=1 );
|
|||||||
*
|
*
|
||||||
* @package PeptideSearchAI
|
* @package PeptideSearchAI
|
||||||
*/
|
*/
|
||||||
|
declare( strict_types=1 );
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
declare( strict_types=1 );
|
|
||||||
/**
|
/**
|
||||||
* Browsable peptide directory — REST endpoint, shortcode, and data formatting.
|
* Browsable peptide directory — REST endpoint, shortcode, and data formatting.
|
||||||
*
|
*
|
||||||
@@ -12,6 +11,7 @@ declare( strict_types=1 );
|
|||||||
* @see includes/class-psa-search.php — existing search shortcode (separate from directory)
|
* @see includes/class-psa-search.php — existing search shortcode (separate from directory)
|
||||||
* @see assets/js/psa-directory.js — frontend grid, filter, modal logic
|
* @see assets/js/psa-directory.js — frontend grid, filter, modal logic
|
||||||
*/
|
*/
|
||||||
|
declare( strict_types=1 );
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
declare( strict_types=1 );
|
|
||||||
/**
|
/**
|
||||||
* Handles encryption/decryption of sensitive data at rest.
|
* Handles encryption/decryption of sensitive data at rest.
|
||||||
*
|
*
|
||||||
@@ -11,6 +10,7 @@ declare( strict_types=1 );
|
|||||||
* @see includes/class-psa-admin.php
|
* @see includes/class-psa-admin.php
|
||||||
* @see includes/class-psa-ai-generator.php
|
* @see includes/class-psa-ai-generator.php
|
||||||
*/
|
*/
|
||||||
|
declare( strict_types=1 );
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
declare( strict_types=1 );
|
|
||||||
/**
|
/**
|
||||||
* Echo Knowledge Base article builder for generated peptide content.
|
* Echo Knowledge Base article builder for generated peptide content.
|
||||||
*
|
*
|
||||||
@@ -11,6 +10,7 @@ declare( strict_types=1 );
|
|||||||
* @package PeptideSearchAI
|
* @package PeptideSearchAI
|
||||||
* @see includes/class-psa-ai-generator.php
|
* @see includes/class-psa-ai-generator.php
|
||||||
*/
|
*/
|
||||||
|
declare( strict_types=1 );
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
declare( strict_types=1 );
|
|
||||||
/**
|
/**
|
||||||
* OpenRouter API communication layer.
|
* OpenRouter API communication layer.
|
||||||
*
|
*
|
||||||
@@ -12,6 +11,7 @@ declare( strict_types=1 );
|
|||||||
* @see includes/class-psa-ai-generator.php
|
* @see includes/class-psa-ai-generator.php
|
||||||
* @see includes/class-psa-cost-tracker.php
|
* @see includes/class-psa-cost-tracker.php
|
||||||
*/
|
*/
|
||||||
|
declare( strict_types=1 );
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
@@ -90,15 +90,15 @@ class PSA_OpenRouter {
|
|||||||
array(
|
array(
|
||||||
'timeout' => 120,
|
'timeout' => 120,
|
||||||
'headers' => array(
|
'headers' => array(
|
||||||
'Content-Type' => 'application/json',
|
'Content-Type' => 'application/json',
|
||||||
'Authorization' => 'Bearer ' . $api_key,
|
'Authorization' => 'Bearer ' . $api_key,
|
||||||
'HTTP-Referer' => $site_url,
|
'HTTP-Referer' => $site_url,
|
||||||
'X-Title' => $site_name,
|
'X-Title' => $site_name,
|
||||||
),
|
),
|
||||||
'body' => wp_json_encode(
|
'body' => wp_json_encode(
|
||||||
array(
|
array(
|
||||||
'model' => $model,
|
'model' => $model,
|
||||||
'messages' => array(
|
'messages' => array(
|
||||||
array(
|
array(
|
||||||
'role' => 'system',
|
'role' => 'system',
|
||||||
'content' => 'You are a scientific database assistant. Return only valid JSON.',
|
'content' => 'You are a scientific database assistant. Return only valid JSON.',
|
||||||
@@ -108,8 +108,8 @@ class PSA_OpenRouter {
|
|||||||
'content' => $prompt,
|
'content' => $prompt,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'max_tokens' => $max_tokens,
|
'max_tokens' => $max_tokens,
|
||||||
'temperature' => 0.3,
|
'temperature' => 0.3,
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -152,13 +152,13 @@ class PSA_OpenRouter {
|
|||||||
|
|
||||||
PSA_Cost_Tracker::log_api_call(
|
PSA_Cost_Tracker::log_api_call(
|
||||||
array(
|
array(
|
||||||
'provider' => 'openrouter',
|
'provider' => 'openrouter',
|
||||||
'model' => $model,
|
'model' => $model,
|
||||||
'prompt_tokens' => $prompt_tokens,
|
'prompt_tokens' => $prompt_tokens,
|
||||||
'completion_tokens' => $completion_tokens,
|
'completion_tokens' => $completion_tokens,
|
||||||
'request_type' => $request_type,
|
'request_type' => $request_type,
|
||||||
'peptide_name' => $peptide_name,
|
'peptide_name' => $peptide_name,
|
||||||
'success' => true,
|
'success' => true,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
declare( strict_types=1 );
|
|
||||||
/**
|
/**
|
||||||
* Registers the Peptide custom post type, taxonomy, and meta fields.
|
* Registers the Peptide custom post type, taxonomy, and meta fields.
|
||||||
*
|
*
|
||||||
@@ -11,6 +10,7 @@ declare( strict_types=1 );
|
|||||||
* @see includes/class-psa-ai-generator.php — auto-assigns category term after generation
|
* @see includes/class-psa-ai-generator.php — auto-assigns category term after generation
|
||||||
* @see includes/class-psa-directory.php — reads taxonomy for directory filtering
|
* @see includes/class-psa-directory.php — reads taxonomy for directory filtering
|
||||||
*/
|
*/
|
||||||
|
declare( strict_types=1 );
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
declare( strict_types=1 );
|
|
||||||
/**
|
/**
|
||||||
* PubChem PUG REST API integration for molecular data enrichment.
|
* PubChem PUG REST API integration for molecular data enrichment.
|
||||||
*
|
*
|
||||||
@@ -10,6 +9,7 @@ declare( strict_types=1 );
|
|||||||
* @package PeptideSearchAI
|
* @package PeptideSearchAI
|
||||||
* @see includes/class-psa-ai-generator.php
|
* @see includes/class-psa-ai-generator.php
|
||||||
*/
|
*/
|
||||||
|
declare( strict_types=1 );
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
declare( strict_types=1 );
|
|
||||||
/**
|
/**
|
||||||
* Handles AJAX search, the [peptide_search] shortcode, and the REST API endpoint.
|
* Handles AJAX search, the [peptide_search] shortcode, and the REST API endpoint.
|
||||||
*
|
*
|
||||||
@@ -11,6 +10,7 @@ declare( strict_types=1 );
|
|||||||
* @see includes/class-psa-ai-generator.php
|
* @see includes/class-psa-ai-generator.php
|
||||||
* @see includes/class-psa-config.php
|
* @see includes/class-psa-config.php
|
||||||
*/
|
*/
|
||||||
|
declare( strict_types=1 );
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
declare( strict_types=1 );
|
|
||||||
/**
|
/**
|
||||||
* Custom template rendering for single peptide pages.
|
* Custom template rendering for single peptide pages.
|
||||||
*
|
*
|
||||||
@@ -11,6 +10,7 @@ declare( strict_types=1 );
|
|||||||
* @see includes/class-psa-post-type.php
|
* @see includes/class-psa-post-type.php
|
||||||
* @see includes/class-psa-directory.php — detail modal uses the same data via REST
|
* @see includes/class-psa-directory.php — detail modal uses the same data via REST
|
||||||
*/
|
*/
|
||||||
|
declare( strict_types=1 );
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
|
|||||||
@@ -129,20 +129,20 @@ function psa_enqueue_frontend_assets() {
|
|||||||
'ajaxurl' => admin_url( 'admin-ajax.php' ),
|
'ajaxurl' => admin_url( 'admin-ajax.php' ),
|
||||||
'nonce' => wp_create_nonce( 'psa_search_nonce' ),
|
'nonce' => wp_create_nonce( 'psa_search_nonce' ),
|
||||||
'i18n' => array(
|
'i18n' => array(
|
||||||
'error' => __( 'Error:', 'peptide-search-ai' ),
|
'error' => __( 'Error:', 'peptide-search-ai' ),
|
||||||
'searchFailed' => __( 'Search failed.', 'peptide-search-ai' ),
|
'searchFailed' => __( 'Search failed.', 'peptide-search-ai' ),
|
||||||
'unexpected' => __( 'Unexpected response.', 'peptide-search-ai' ),
|
'unexpected' => __( 'Unexpected response.', 'peptide-search-ai' ),
|
||||||
'rateLimited' => __( 'Too many requests. Please try again later.', 'peptide-search-ai' ),
|
'rateLimited' => __( 'Too many requests. Please try again later.', 'peptide-search-ai' ),
|
||||||
'networkError' => __( 'Could not connect to the server. Please try again.', 'peptide-search-ai' ),
|
'networkError' => __( 'Could not connect to the server. Please try again.', 'peptide-search-ai' ),
|
||||||
'timeout' => __( 'Request timed out. The server took too long to respond. Please try again.', 'peptide-search-ai' ),
|
'timeout' => __( 'Request timed out. The server took too long to respond. Please try again.', 'peptide-search-ai' ),
|
||||||
'connectionError' => __( 'Network error. Please check your connection and try again.', 'peptide-search-ai' ),
|
'connectionError' => __( 'Network error. Please check your connection and try again.', 'peptide-search-ai' ),
|
||||||
'serverError' => __( 'Server error. Please try again later.', 'peptide-search-ai' ),
|
'serverError' => __( 'Server error. Please try again later.', 'peptide-search-ai' ),
|
||||||
'unavailable' => __( 'Server is temporarily unavailable. Please try again later.', 'peptide-search-ai' ),
|
'unavailable' => __( 'Server is temporarily unavailable. Please try again later.', 'peptide-search-ai' ),
|
||||||
'peptidesFound' => __( 'peptide(s) found', 'peptide-search-ai' ),
|
'peptidesFound' => __( 'peptide(s) found', 'peptide-search-ai' ),
|
||||||
'pendingMsg' => __( 'is currently being added to our database. Please check back again later.', 'peptide-search-ai' ),
|
'pendingMsg' => __( 'is currently being added to our database. Please check back again later.', 'peptide-search-ai' ),
|
||||||
'invalidMsg' => __( 'does not appear to be a recognized peptide. Please check the spelling or try a different search term.', 'peptide-search-ai' ),
|
'invalidMsg' => __( 'does not appear to be a recognized peptide. Please check the spelling or try a different search term.', 'peptide-search-ai' ),
|
||||||
'verified' => __( 'Verified', 'peptide-search-ai' ),
|
'verified' => __( 'Verified', 'peptide-search-ai' ),
|
||||||
'curated' => __( 'Curated', 'peptide-search-ai' ),
|
'curated' => __( 'Curated', 'peptide-search-ai' ),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -116,9 +116,9 @@ class AIGeneratorTest extends TestCase {
|
|||||||
*/
|
*/
|
||||||
public function test_parse_response_with_markdown_fences() {
|
public function test_parse_response_with_markdown_fences() {
|
||||||
$response_text = <<<JSON
|
$response_text = <<<JSON
|
||||||
\`\`\`json
|
```json
|
||||||
{"is_valid": true, "canonical_name": "Semaglutide", "reason": "GLP-1 agonist"}
|
{"is_valid": true, "canonical_name": "Semaglutide", "reason": "GLP-1 agonist"}
|
||||||
\`\`\`
|
```
|
||||||
JSON;
|
JSON;
|
||||||
|
|
||||||
$result = PSA_OpenRouter::parse_response( $response_text );
|
$result = PSA_OpenRouter::parse_response( $response_text );
|
||||||
|
|||||||
Reference in New Issue
Block a user