references/anti-patterns.md
A supporting file of the wp-patterns skill.
Anti-Patterns
Common mistakes that produce generic, broken, or inaccessible patterns.
Design Quality Checklist
- Not generic: pattern makes at least 3 distinctive design choices
- Layout variety: not defaulting to 3 equal columns or uniform symmetric layouts
- Color rhythm: sections alternate or vary backgrounds — not all the same
- Typography contrast: headings clearly distinct from body (size, family, or weight)
- Spatial intention: padding and gaps vary by context, not uniform everywhere
- Meaningful content: placeholder text reflects real use, buttons describe actions
- Specific structure: comparisons, timelines, schedules, pricing, menus, and documentation cards have labels that make sense without relying on visual position alone
- Restrained but distinctive: corporate/professional patterns still include a clear hierarchy, accent, or layout choice; playful patterns do not become a one-note palette or repeated gradient treatment
Technical Anti-Patterns
Inline Styles and Custom CSS
<!-- WRONG: inline <style> tag -->
<style>.my-custom-hero { background: linear-gradient(...); }</style>
<!-- WRONG: custom CSS class not from blocks -->
<div class="my-custom-card">
<!-- CORRECT: use block attributes -->
<!-- wp:group {"style":{"color":{"gradient":"linear-gradient(...)"}}} -->Hardcoded Colors
// WRONG: hardcoded hex when a preset exists
{"style":{"color":{"background":"#000000","text":"#ffffff"}}}
// CORRECT: use theme presets for theme compatibility
{"backgroundColor":"contrast","textColor":"base"}Use hardcoded values only when no suitable preset exists and the design requires a specific color.
Missing Escaping and i18n
// WRONG: raw text, not translatable, not escaped
<h2>Our Services</h2>
// WRONG: translatable but not escaped
<h2><?php _e( 'Our Services', 'theme-slug' ); ?></h2>
// CORRECT: escaped and translatable
<h2><?php esc_html_e( 'Our Services', 'theme-slug' ); ?></h2>Query-Dependent PHP
// WRONG: runs at registration time, not render time
<?php $recent = get_posts( array( 'numberposts' => 3 ) ); ?>
// CORRECT: use Query Loop block for dynamic content
<!-- wp:query {"query":{"perPage":3,"postType":"post"}} -->Unclosed or Mismatched Blocks
<!-- WRONG: missing closing comment -->
<!-- wp:group -->
<div class="wp-block-group">
<!-- wp:heading -->
<h2>Title</h2>
<!-- /wp:heading -->
<!-- Missing: /wp:group -->
<!-- WRONG: mismatched nesting -->
<!-- wp:group -->
<!-- wp:columns -->
<!-- /wp:group -->
<!-- /wp:columns -->Placeholder Image URLs
<!-- WRONG: external placeholder service -->
<img src="https://via.placeholder.com/800x400" alt=""/>
<!-- CORRECT: use theme assets or descriptive placeholder -->
<img src="<?php echo esc_url( get_theme_file_uri( 'assets/images/placeholder.webp' ) ); ?>"
alt="<?php esc_attr_e( 'Featured image', 'theme-slug' ); ?>"/>Accessibility Failures
Missing Alt Text
<!-- WRONG -->
<!-- wp:image -->
<figure class="wp-block-image"><img src="photo.jpg" alt=""/></figure>
<!-- /wp:image -->
<!-- CORRECT: descriptive alt for informational images -->
<!-- wp:image {"alt":"Team members collaborating around a whiteboard"} -->Decorative images (backgrounds, dividers) can use empty alt, but informational images must describe content.
Skipped Heading Levels
<!-- WRONG: jumps from h2 to h5 -->
<!-- wp:heading {"level":2} --> Section Title
<!-- wp:heading {"level":5} --> Subsection
<!-- CORRECT: sequential levels -->
<!-- wp:heading {"level":2} --> Section Title
<!-- wp:heading {"level":3} --> SubsectionPatterns should use h2 as the top level (h1 is the page title). Descend sequentially: h2 → h3 → h4.
Insufficient Color Contrast
When using dark backgrounds, verify text presets provide adequate contrast:
{"backgroundColor":"contrast","textColor":"base"}— typically safe (dark bg, light text)- Custom color combinations must meet WCAG 2.1 AA (4.5:1 for body text, 3:1 for large text)
Non-Descriptive Button Text
<!-- WRONG -->
<a class="wp-block-button__link">Click Here</a>
<a class="wp-block-button__link">Read More</a>
<!-- CORRECT: describes the action or destination -->
<a class="wp-block-button__link"><?php esc_html_e( 'View Our Services', 'theme-slug' ); ?></a>
<a class="wp-block-button__link"><?php esc_html_e( 'Download the Report', 'theme-slug' ); ?></a>Missing ARIA on Decorative Elements
Spacer blocks should include aria-hidden="true" (WordPress adds this automatically). If generating custom separator patterns, ensure decorative elements don't announce to screen readers.
Technical Validation Checklist
- Every
<!-- wp:block -->has matching<!-- /wp:block --> - JSON in block comments is valid (no trailing commas, strings double-quoted)
- All user-visible strings use
esc_html_e()oresc_html__() - All URLs use
esc_url() - All attribute values with translatable text use
esc_attr_e()oresc_attr__() - Informational images have descriptive translated alt text; decorative images use empty alt text intentionally
- Heading levels are sequential (h2 → h3 → h4, never skip)
- Preset slugs are valid defaults or documented as theme-specific
-
Slugin header uses correct namespace:theme-slug/pattern-name - No inline
<style>, no<script>, no custom CSS classes - No query-dependent PHP functions
- Button/link labels are action-specific; avoid vague labels such as "Click Here" or "Read More"
- Updating an existing pattern preserves the
Slugunless intentionally creating a new pattern