feat: brand identity v1.0.0 — Direction C Trusted Guide (theme v2.0.0-alpha.1)

Implements weeks 1–4 of the CMO brand identity sprint. Complete theme reskin with:

- CSS token system (brand.css) with Teal/Lime/Orange palette
- Poppins/Inter/IBM Plex Mono font loading
- Full favicon/PWA/OG asset pack
- 5-state verdict badge + card + evidence row components
- verdict_state post meta on pr_peptide CPT with meta box
- Affiliate disclosure component (3 contexts: inline, banner, footer)
- How we review peptides page template
- About & Editorial Standards page template
- Footer Our Method links + disclosure
- SVG logo support (logo-horizontal.svg inline)
- OG image fallback meta tag
- Accessibility: role=img on badges, skip-to-content link, prefers-reduced-motion support

Theme version bumped to 2.0.0-alpha.1.
This commit is contained in:
peptiderepo
2026-04-25 19:47:31 +00:00
parent e40602d58c
commit a2bff59cf1
39 changed files with 894 additions and 4 deletions

View File

@@ -0,0 +1,52 @@
<?php
/**
* Affiliate Disclosure Component
*
* Displays FTC-compliant disclosure about affiliate commissions.
* Three contexts: inline (default), banner, footer.
* Accepts $args['context'].
*
* @package peptide-starter
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$context = isset( $args['context'] ) ? sanitize_text_field( $args['context'] ) : 'inline';
// Copy variants (verbatim per CMO spec).
$inline_copy = 'If you buy through this link, the seller pays Peptide Repo a commission. We don\'t pay to feature any peptide, and our verdicts don\'t change based on who pays.';
$banner_copy = 'Peptide Repo earns a commission when readers buy through links to our fulfillment partners. We are funded by those commissions, not by the peptide brands themselves. No peptide on this site appears here because someone paid us. Our verdicts are decided before we negotiate any partnership, and we drop partners whose product or process degrades.';
$footer_copy = 'Peptide Repo earns a commission on some links. <a href="' . esc_url( home_url( '/about/' ) ) . '#disclosures">' . esc_html__( 'How we work', 'peptide-starter' ) . ' →</a>';
switch ( $context ) {
case 'banner':
?>
<aside class="pr-disclosure pr-disclosure--banner" aria-label="<?php esc_attr_e( 'Affiliate disclosure', 'peptide-starter' ); ?>">
<span class="pr-disclosure__label"><?php esc_html_e( 'A note on commerce.', 'peptide-starter' ); ?></span>
<?php echo wp_kses_post( $banner_copy ); ?>
</aside>
<?php
break;
case 'footer':
?>
<p class="pr-disclosure pr-disclosure--footer">
<?php echo wp_kses_post( $footer_copy ); ?>
</p>
<?php
break;
case 'inline':
default:
?>
<aside class="pr-disclosure pr-disclosure--inline" aria-label="<?php esc_attr_e( 'Affiliate disclosure', 'peptide-starter' ); ?>">
<span class="pr-disclosure__label"><?php esc_html_e( 'How we make money:', 'peptide-starter' ); ?></span>
<?php echo wp_kses_post( $inline_copy ); ?>
</aside>
<?php
break;
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* Verdict Badge Component
*
* Displays a verdict state badge with glyph, label, and colors.
* Accepts $args['verdict_state'] and $args['show_label'].
*
* @package peptide-starter
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$verdict_state = isset( $args['verdict_state'] ) ? sanitize_text_field( $args['verdict_state'] ) : '';
$show_label = isset( $args['show_label'] ) ? (bool) $args['show_label'] : true;
// State configuration.
$states = array(
'established' => array( 'glyph' => '✓', 'label' => 'Established' ),
'promising' => array( 'glyph' => '◐', 'label' => 'Promising' ),
'investigational' => array( 'glyph' => '?', 'label' => 'Investigational' ),
'insufficient' => array( 'glyph' => '⊘', 'label' => 'Insufficient Evidence' ),
'cautionary' => array( 'glyph' => '⚠', 'label' => 'Cautionary' ),
);
// Early exit if invalid state.
if ( ! isset( $states[ $verdict_state ] ) ) {
return;
}
$state_info = $states[ $verdict_state ];
?>
<span class="pr-verdict pr-verdict--<?php echo esc_attr( $verdict_state ); ?>" role="img" aria-label="<?php echo esc_attr( 'Verdict: ' . $state_info['label'] ); ?>">
<span class="pr-verdict__glyph" aria-hidden="true"><?php echo $state_info['glyph']; ?></span>
<?php if ( $show_label ) : ?>
<span class="pr-verdict__label"><?php echo esc_html( $state_info['label'] ); ?></span>
<?php endif; ?>
</span>

View File

@@ -0,0 +1,99 @@
<?php
/**
* Verdict Card Component (Monograph Hero)
*
* Displays a full verdict card for a pr_peptide post.
* Reads verdict_state and signal_row_1/2/3 from post meta.
* Accepts $args['post_id'].
*
* @package peptide-starter
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$post_id = isset( $args['post_id'] ) ? absint( $args['post_id'] ) : get_the_ID();
// Get verdict state from post meta.
$verdict_state = get_post_meta( $post_id, 'verdict_state', true );
// Early exit if no verdict state is set.
if ( empty( $verdict_state ) ) {
return;
}
// Collect signal rows.
$signals = array();
for ( $i = 1; $i <= 3; $i++ ) {
$signal_text = get_post_meta( $post_id, 'signal_row_' . $i, true );
if ( ! empty( $signal_text ) ) {
$signals[] = array(
'glyph' => $i === 1 ? '✓' : ( $i === 2 ? '!' : '?' ),
'label' => $signal_text,
);
}
}
$post = get_post( $post_id );
?>
<div class="pr-verdict-card">
<div class="pr-verdict-card__header">
<div>
<?php
get_template_part(
'template-parts/verdict/badge',
null,
array(
'verdict_state' => $verdict_state,
'show_label' => true,
)
);
?>
</div>
<time class="pr-verdict-card__updated" datetime="<?php echo esc_attr( get_the_date( 'c', $post_id ) ); ?>">
<?php echo esc_html( 'Updated ' . get_the_date( 'M d, Y', $post_id ) ); ?>
</time>
</div>
<h1 class="pr-verdict-card__title"><?php echo esc_html( get_the_title( $post_id ) ); ?></h1>
<p class="pr-verdict-card__summary">
<?php
// Get post excerpt or first 100 chars of content.
$summary = get_the_excerpt( $post_id );
if ( empty( $summary ) ) {
$content = get_the_content( null, false, $post_id );
$summary = wp_trim_words( $content, 20 );
}
echo wp_kses_post( $summary );
?>
</p>
<?php if ( ! empty( $signals ) ) : ?>
<?php
get_template_part(
'template-parts/verdict/evidence-row',
null,
array( 'signals' => $signals )
);
?>
<?php endif; ?>
<div class="pr-verdict-card__verdict-label"><?php esc_html_e( 'Our verdict:', 'peptide-starter' ); ?></div>
<div class="pr-verdict-card__verdict-text">
<?php
// Placeholder verdict text; can be extended with a custom meta field.
echo esc_html__( 'This peptide merits careful scientific review. Please consult with a healthcare provider before use.', 'peptide-starter' );
?>
</div>
<div class="pr-verdict-card__cta-group">
<a href="#evidence" class="pr-verdict-card__cta-link">
<?php esc_html_e( 'Read the full evidence', 'peptide-starter' ); ?> →
</a>
<a href="#dosing" class="pr-verdict-card__cta-link">
<?php esc_html_e( 'Jump to dosing', 'peptide-starter' ); ?> →
</a>
</div>
</div>

View File

@@ -0,0 +1,34 @@
<?php
/**
* Verdict Evidence Signal Row Component
*
* Displays an inset row of evidence signals with glyphs.
* Accepts $args['signals'] as array of ['glyph' => '...', 'label' => '...']
*
* @package peptide-starter
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$signals = isset( $args['signals'] ) && is_array( $args['signals'] ) ? $args['signals'] : array();
if ( empty( $signals ) ) {
return;
}
?>
<div class="pr-evidence-row">
<?php foreach ( $signals as $signal ) : ?>
<?php
$glyph = isset( $signal['glyph'] ) ? sanitize_text_field( $signal['glyph'] ) : '';
$label = isset( $signal['label'] ) ? sanitize_text_field( $signal['label'] ) : '';
?>
<?php if ( ! empty( $glyph ) && ! empty( $label ) ) : ?>
<div class="pr-evidence-row__item">
<span class="pr-evidence-row__glyph"><?php echo esc_html( $glyph ); ?></span>
<span><?php echo esc_html( $label ); ?></span>
</div>
<?php endif; ?>
<?php endforeach; ?>
</div>