# Peptide Starter Theme - Conventions & Development Guide ## Naming Conventions ### PHP Functions All custom PHP functions are prefixed with `peptide_starter_`: ```php // Good function peptide_starter_get_hero_title() { } function peptide_starter_setup() { } function peptide_starter_widgets_init() { } function peptide_starter_pagination() { } // Bad function get_hero_title() { } function setup_theme() { } ``` **Pattern:** `peptide_starter_{verb}_{noun}` or `peptide_starter_get_{option}` **Common function types:** - `peptide_starter_get_*()` — Retrieve theme mod or option - `peptide_starter_{noun}_init()` — Initialization functions - `peptide_starter_is_*()` — Boolean checks - `peptide_starter_render_*()` — Output HTML ### CSS Classes All theme CSS classes are prefixed with `.ps-`: ```css /* Components */ .ps-btn /* Button component */ .ps-btn-primary /* Button variant */ .ps-btn-sm /* Button size */ .ps-card /* Card component */ .ps-badge /* Badge component */ .ps-alert-info /* Alert variant */ /* Utilities */ .ps-container /* Max-width wrapper */ .ps-pagination /* Pagination nav */ .ps-search-form /* Search form */ .ps-search-input /* Search input */ /* Regions */ .site-header /* No prefix; global region */ .site-footer /* No prefix; global region */ .site-main /* No prefix; global region */ .hero-section /* Hero region specific */ ``` **Pattern:** `.ps-{component}` for components, `.ps-{component}-{variant}` for variants **Reserved prefixes (do not use):** - `.pn-*` — Peptide News plugin - `.psa-*` — Peptide Search AI plugin - `.prab-*` — PRAutoBlogger plugin ### CSS Variables (Custom Properties) All design tokens are defined in `style.css :root`: ```css /* Colors */ --text-primary /* Main text color */ --text-secondary /* Secondary text color */ --bg-primary /* Main background */ --bg-secondary /* Secondary background */ /* Spacing (8px grid base) */ --spacing-xs: 4px /* 0.5 × base */ --spacing-sm: 8px /* 1 × base */ --spacing-md: 16px /* 2 × base */ --spacing-lg: 24px /* 3 × base */ --spacing-xl: 32px /* 4 × base */ /* Typography */ --font-sans /* Primary font family */ --font-mono /* Monospace font */ --text-h1 /* H1 size */ --text-h1-weight /* H1 weight */ ``` **Usage:** ```css .ps-card { padding: var(--spacing-md); color: var(--text-primary); } ``` ### Template Part Naming Template parts in `template-parts/` follow WordPress convention: ``` template-parts/content.php /* Default loop item */ template-parts/content-{post-type}.php /* CPT-specific */ template-parts/content-none.php /* Empty state */ template-parts/{section}-{name}.php /* Specific parts (if added) */ ``` **Calling template parts:** ```php get_template_part( 'template-parts/content', get_post_type() ); get_template_part( 'template-parts/content', 'none' ); ``` ### Hook Names Custom hooks use the `peptide_starter_` prefix: ```php // Filters apply_filters( 'peptide_starter_show_newsletter', true ); // Actions (if any added in future) do_action( 'peptide_starter_hero_before' ); ``` ### File Organization - **Root:** Theme core files (functions.php, header.php, footer.php, etc.) - **assets/js/:** Client-side scripts only; no bundling - **assets/css/:** (None; all CSS in style.css) - **languages/:** Translation files - **template-parts/:** Reusable template parts ## Step-by-Step Guides ### How to Add a New Template **Scenario:** Create a custom landing page template 1. Create file: `landing-{name}.php` ```php
Template dropdown 4. Test the template: - Create/edit a page and select the template - Verify hero, dark mode toggle, footer all appear correctly **Best practices:** - Always include `get_header()` and `get_footer()` - Wrap main content in `
` - Use `.ps-container` for consistent max-width - Use existing component classes (`.ps-card`, `.ps-btn`, etc.) - Keep templates under 150 lines; extract complex parts to `template-parts/` ### How to Add a New Plugin Integration **Scenario:** Integrate a new plugin (e.g., "Research Database") via shortcode 1. **In front-page.php**, add a conditional shortcode block: ```php

``` 2. **In functions.php**, optionally add inline overrides if plugin CSS needs adjustment: ```php function peptide_starter_plugin_overrides() { wp_add_inline_style( 'peptide-starter-style', ' /* Override plugin styles here */ .rdb-card { /* example */ } ' ); } add_action( 'wp_enqueue_scripts', 'peptide_starter_plugin_overrides', 99 ); ``` 3. **Document the integration** in CLAUDE.md: - Plugin namespace (e.g., `.rdb-*`) - Shortcode name and parameters - Expected styling classes 4. **If plugin needs dark mode coordination:** - Ask plugin author to listen to `themechange` event (see ARCHITECTURE.md) - Or have plugin read `html[data-theme]` attribute - Provide plugin with CSS custom properties: `getComputedStyle(document.documentElement).getPropertyValue('--text-primary')` 5. **Test:** - Activate plugin and visit front page - Verify shortcode renders - Toggle dark mode; verify plugin responds - Deactivate plugin; verify page still renders (fallback gracefully) **Important:** Always wrap shortcodes in `shortcode_exists()` checks so theme doesn't break if plugin is missing. ### How to Add a New CSS Component **Scenario:** Create a new "pill" button style (small, rounded, inline) 1. **In style.css**, find the Components section (around line 500) 2. **Add new component class:** ```css /* Pill buttons */ .ps-btn-pill { display: inline-block; padding: var(--spacing-xs) var(--spacing-sm); border-radius: 9999px; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; } .ps-btn-pill.ps-btn-primary { background-color: var(--color-primary); color: white; } .ps-btn-pill.ps-btn-secondary { background-color: transparent; border: 1px solid var(--color-primary); color: var(--color-primary); } ``` 3. **Add dark mode support** (in Dark Mode section, around line 1200): ```css html[data-theme="dark"] .ps-btn-pill.ps-btn-secondary { border-color: var(--color-primary-dark); color: var(--color-primary-dark); } ``` 4. **Add responsive sizes if needed** (in Responsive section, around line 1400): ```css @media (max-width: 767px) { .ps-btn-pill { padding: var(--spacing-xs) var(--spacing-xs); } } ``` 5. **Usage in templates:** ```html Beta ``` 6. **Test:** - Light mode: verify colors, sizing, alignment - Dark mode: toggle and verify contrast - Mobile (480px): verify responsive adjustments - Keyboard: focus state should be visible **Best practices:** - Use CSS variables (`var(--spacing-*)`, `var(--color-*)`) not hardcoded values - Avoid `!important` unless absolutely necessary - Include dark mode support immediately (no `.ps-*` is light-only) - Group related rules with comments - Keep component definitions self-contained (<100 lines) ### How to Add a New Customizer Setting **Scenario:** Add a new "Primary Accent Color" customizer option 1. **In functions.php** (around line 143), add a new section: ```php $wp_customize->add_section( 'peptide_starter_colors', array( 'title' => esc_html__( 'Colors', 'peptide-starter' ), 'priority' => 45, ) ); ``` 2. **Add a setting:** ```php $wp_customize->add_setting( 'primary_accent_color', array( 'default' => '#0066CC', 'transport' => 'postMessage', 'sanitize_callback' => 'sanitize_hex_color', ) ); ``` 3. **Add a control:** ```php $wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'primary_accent_color', array( 'label' => esc_html__( 'Primary Accent Color', 'peptide-starter' ), 'section' => 'peptide_starter_colors', 'settings' => 'primary_accent_color', ) ) ); ``` 4. **Create a getter function:** ```php function peptide_starter_get_primary_accent_color() { return get_theme_mod( 'primary_accent_color', '#0066CC' ); } ``` 5. **Output in front-end** (e.g., in footer.php): ```php ``` Or better, use inline style in `wp_head`: ```php function peptide_starter_custom_colors() { $accent = peptide_starter_get_primary_accent_color(); ?> 'postMessage'` — Instant preview (needs JS listener) - `'transport' => 'refresh'` — Full page refresh For color/text changes, use `postMessage` with a JS listener in theme.js: ```javascript wp_customize.bind( 'setting:primary_accent_color', function( setting ) { setting.bind( function( newval ) { document.documentElement.style.setProperty('--color-accent', newval); }); }); ``` ## Error Handling Patterns ### Theme Doesn't Break If Plugin Missing **Pattern: Graceful Degradation** ```php // Good — shortcode_exists check if ( shortcode_exists( 'peptide_search' ) ) { echo do_shortcode( '[peptide_search]' ); } else { get_search_form(); // Fallback to WordPress default } // Bad — assumes plugin exists echo do_shortcode( '[peptide_search]' ); // Renders [peptide_search] as text if missing ``` ### Menu Fallback **In header.php:** ```php wp_nav_menu( array( 'theme_location' => 'primary', 'fallback_cb' => 'peptide_starter_primary_menu_fallback', // Function defined in header 'walker' => new Peptide_Starter_Nav_Walker(), ) ); function peptide_starter_primary_menu_fallback() { // Renders Home, About, Peptides links if no menu assigned } ``` ### Widget Area Check **In footer.php:** ```php if ( is_active_sidebar( 'footer-1' ) ) { dynamic_sidebar( 'footer-1' ); } else { // Render default content echo '

' . esc_html__( 'About', 'peptide-starter' ) . '

'; } ``` ### Class Existence Check **For WooCommerce:** ```php if ( class_exists( 'WooCommerce' ) ) { // Render cart icon } ``` **For post types:** ```php if ( post_type_exists( 'peptide' ) ) { echo '' . __( 'Peptides' ) . ''; } ``` ### Input Validation All user-facing output must be escaped: ```php // Good echo esc_html( get_the_title() ); echo esc_url( home_url( '/' ) ); echo esc_attr( $html_attribute_value ); // Bad echo get_the_title(); echo home_url( '/' ); ``` ## Dark Mode Implementation Guide ### How Dark Mode Works in Peptide Starter 1. **Inline script in `wp_head`** (functions.php, line 406-422) - Runs immediately before CSS loads - Prevents white flash by setting `html[data-theme]` early - Checks in order: localStorage → system pref → customizer default 2. **CSS selectors** (style.css, line ~1200 "Dark Mode") - Light mode: default colors in `:root` - Dark mode: `html[data-theme="dark"]` selector overrides 3. **JavaScript listener** (theme.js, line 47-63) - Responds to dark mode toggle button - Updates localStorage - Dispatches `themechange` event to plugins - Updates sun/moon icon visibility ### Adding Dark Mode to a New Component **Example: New Alert Style** 1. **Define light mode in CSS:** ```css .ps-alert-custom { padding: var(--spacing-md); background-color: #E3F2FD; /* Light blue */ color: #0D47A1; /* Dark blue text */ border: 1px solid #90CAF9; } ``` 2. **Add dark mode override:** ```css html[data-theme="dark"] .ps-alert-custom { background-color: #1A237E; /* Dark blue bg */ color: #E3F2FD; /* Light text */ border-color: #3F51B5; /* Darker border */ } ``` 3. **Test:** - Load page in light mode → verify colors - Toggle dark mode → verify override colors are applied - Open DevTools → verify `html[data-theme="dark"]` attribute set - Check localStorage `peptide-starter-theme` is updated ### Helping Plugins Support Dark Mode **If a plugin doesn't listen to dark mode changes:** 1. Ask plugin author to listen to the `themechange` event: ```javascript document.addEventListener('themechange', (e) => { const theme = e.detail.theme; // Update plugin styles based on theme }); ``` 2. Or use a MutationObserver to watch for `data-theme` changes: ```javascript const observer = new MutationObserver(() => { const theme = document.documentElement.getAttribute('data-theme'); // Update styles }); observer.observe(document.documentElement, { attributes: true }); ``` 3. Or read CSS variables in the plugin stylesheet: ```css .plugin-card { color: var(--text-primary); background-color: var(--bg-secondary); } ``` ### CSS Variables for Dark Mode All available variables (defined in `:root`): ```css --text-primary /* Main text (light: #111827, dark: #F9FAFB) */ --text-secondary /* Secondary text (light: #6B7280, dark: #D1D5DB) */ --bg-primary /* Main background (light: #FFFFFF, dark: #111827) */ --bg-secondary /* Secondary bg (light: #F3F4F6, dark: #1F2937) */ --color-primary /* Primary accent (light: #0066CC, dark: #3B82F6) */ --border-color /* Border color (light: #E5E7EB, dark: #374151) */ ``` ## Testing Checklist When modifying the theme, verify: - [ ] **Light mode** — All text readable, colors correct - [ ] **Dark mode** — Toggle to dark, verify colors swap, no white flash on reload - [ ] **Mobile** (480px) — Navigation collapses, search/dark mode icons present - [ ] **Tablet** (768px) — Layout adapts, footer 2-column if needed - [ ] **Desktop** (1024px+) — Full layout renders correctly - [ ] **Plugins active** — Shortcodes render, no JS errors in console - [ ] **Plugins inactive** — Graceful fallbacks work (search form, no broken layout) - [ ] **Accessibility** — Tab through page, all interactive elements reachable - [ ] **Focus states** — Every button/link has visible focus outline - [ ] **Keyboard navigation** — Escape closes overlays, arrow keys in menu if relevant ## Common Tasks & Commands **Check JavaScript syntax:** ```bash node --check assets/js/theme.js node --check assets/js/navigation.js ``` **View theme version:** ```php echo PEPTIDE_STARTER_VERSION; // Currently: 1.3.1 ``` **Update theme version (when releasing):** 1. Edit `style.css` line 7: `Version: X.Y.Z` 2. Edit `functions.php` line 14: `define( 'PEPTIDE_STARTER_VERSION', 'X.Y.Z' )` **Deploy to production:** - Push to `main` branch on GitHub - GitHub Actions runs rsync to Hostinger via SSH - LiteSpeed cache clears automatically **Debug active plugins:** ```php // In functions.php or template $active = get_option( 'active_plugins' ); error_log( print_r( $active, true ) ); ``` **View Customizer settings:** ```php echo get_theme_mod( 'hero_title' ); echo get_theme_mod( 'dark_mode_default', false ); ``` ## Related Documentation - **ARCHITECTURE.md** — System design, data flows, integrations - **CLAUDE.md** — Developer context and quick reference - **README.md** — User-facing feature documentation - **CHANGELOG.md** — Version history