Files
peptide-repo-core/includes/frontend/class-pr-core-disclaimer.php
peptiderepo 665d7fa9e1 Adopt reusable CI standard + PHPUnit conversion (#22)
Squash-merge of PR #22: adopt shared reusable CI workflow, convert PHPUnit to stubs, update branch-protection contexts.

QA-approved at 05d8094a1d. All required CI checks green.

Agent-Session: 2026-06-17-prcore-ci-deploy
2026-06-17 01:12:00 +07:00

141 lines
5.2 KiB
PHP

<?php
/**
* Disclaimer.
*
* @package Peptide_Repo_Core
*/
declare(strict_types=1);
/**
* Provides shortcode [pr_disclaimer surface="dosing"] and function
*
* @package Peptide_Repo_Core
*/
/**
* Shared disclaimer component for all peptide data surfaces.
*
* What: Provides shortcode [pr_disclaimer surface="dosing"] and function
* pr_core_render_disclaimer() for rendering surface-specific disclaimers.
* Who calls it: PR_Core::init() registers shortcode; consumer plugins call static methods.
* Dependencies: None (reads from wp_options).
*
* Disclaimer copy is stored in pr_core_disclaimer_copy option (JSON keyed by surface),
* versioned by pr_core_disclaimer_version. Editorial review happens once here,
* not once per consumer plugin.
*
* @see ARCHITECTURE.md — Section 2.8 Shared Disclaimer Component.
*/
class PR_Core_Disclaimer {
/**
* Option key for disclaimer copy (JSON).
*
* @var string Option key for disclaimer copy (JSON).
*/
private const COPY_OPTION = 'pr_core_disclaimer_copy';
/**
* Option key for disclaimer version.
*
* @var string Option key for disclaimer version.
*/
private const VERSION_OPTION = 'pr_core_disclaimer_version';
/**
* Default disclaimer text per surface.
*
* @var array<string, string>
*/
private const DEFAULTS = array(
'dosing' => 'The dosing information presented here is compiled from published peer-reviewed literature and is provided for educational and research purposes only. It does not constitute medical advice, diagnosis, or treatment recommendations. Always consult a licensed healthcare professional before making any decisions based on this information.',
'legal' => 'Legal status information is compiled from publicly available regulatory texts and is current as of the last-verified date shown. Regulatory frameworks change frequently. This information does not constitute legal advice. Verify current regulations with the relevant regulatory authority in your jurisdiction before taking any action.',
'reconstitution' => 'This calculator is provided for educational purposes only. Always verify your calculations independently and consult a licensed healthcare professional. The results are based on the inputs you provide and standard reconstitution mathematics.',
'ai-answer' => 'This response was generated by an AI system and may contain errors or omissions. All claims are grounded in the Peptide Repo corpus and cited sources where possible. This is not medical advice. Always verify information with primary sources and consult a licensed healthcare professional.',
'general' => 'The information on this site is for educational and research purposes only. It is not intended as medical advice, diagnosis, or treatment. Always consult a licensed healthcare professional.',
);
/**
* Register shortcode and any frontend hooks.
*
* @return void
*/
public function register_hooks(): void {
add_shortcode( 'pr_disclaimer', array( $this, 'shortcode_handler' ) );
}
/**
* Shortcode handler: [pr_disclaimer surface="dosing"].
*
* @param array<string, string>|string $atts Shortcode attributes.
* @return string Disclaimer HTML.
*/
public function shortcode_handler( $atts ): string {
$atts = shortcode_atts( array( 'surface' => 'general' ), $atts, 'pr_disclaimer' );
return self::render( sanitize_text_field( $atts['surface'] ) );
}
/**
* Render disclaimer HTML for a given surface.
*
* @param string $surface Surface identifier.
* @return string HTML output.
*/
public static function render( string $surface ): string {
$text = self::get_disclaimer_text( $surface );
return sprintf(
'<div class="pr-core-disclaimer" data-surface="%s" role="note" aria-label="%s"><p>%s</p></div>',
esc_attr( $surface ),
esc_attr__( 'Disclaimer', 'peptide-repo-core' ),
esc_html( $text )
);
}
/**
* Get disclaimer text for a surface. Checks custom copy first, falls back to defaults.
*
* @param string $surface Surface identifier.
* @return string Disclaimer text.
*/
public static function get_disclaimer_text( string $surface ): string {
$custom = get_option( self::COPY_OPTION, '{}' );
$copy = json_decode( $custom, true ) ?: array(); // phpcs:ignore Universal.Operators.DisallowShortTernary.Found
if ( ! empty( $copy[ $surface ] ) ) {
return (string) $copy[ $surface ];
}
return self::DEFAULTS[ $surface ] ?? self::DEFAULTS['general'];
}
/**
* Get current disclaimer version.
*
* @return int
*/
public static function get_version(): int {
return (int) get_option( self::VERSION_OPTION, 1 );
}
/**
* Update disclaimer copy for a surface.
*
* Side effects: updates wp_options.
*
* @param string $surface Surface identifier.
* @param string $text New disclaimer text.
* @return void
*/
public static function update_disclaimer( string $surface, string $text ): void {
$custom = get_option( self::COPY_OPTION, '{}' );
$copy = json_decode( $custom, true ) ?: array(); // phpcs:ignore Universal.Operators.DisallowShortTernary.Found
$copy[ sanitize_text_field( $surface ) ] = sanitize_textarea_field( $text );
update_option( self::COPY_OPTION, wp_json_encode( $copy ) );
update_option( self::VERSION_OPTION, self::get_version() + 1 );
}
}