# Wp Ux Design

> WordPress UX and design enforcement — Core Web Vitals, mobile-first layout, typography, color systems, navigation, page builder patterns, image optimization, form UX, loading and error states, admin UX, and performance checklists with concrete CSS/HTML/PHP examples.

- **Type:** Skill
- **Install:** `agentstack add skill-xonack-wp-ux-design-claude-skill-wp-ux-design`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [xonack](https://agentstack.voostack.com/s/xonack)
- **Installs:** 0
- **Category:** [Content & Media](https://agentstack.voostack.com/c/content-and-media)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [xonack](https://github.com/xonack)
- **Source:** https://github.com/xonack/wp-ux-design-claude-skill/tree/main/skills/wp-ux-design

## Install

```sh
agentstack add skill-xonack-wp-ux-design-claude-skill-wp-ux-design
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# WordPress UX/Design Enforcement

Definitive standards for building WordPress sites that are fast, accessible, and visually consistent. Every rule below is enforceable in code review.

---

## 1. Core Web Vitals for WordPress

### LCP (Largest Contentful Paint) 

```

WordPress-specific: disable lazy-load on the first image via filter.

```php
// functions.php — skip lazy-load on above-fold images
add_filter( 'wp_img_tag_add_loading_attr', function( $value, $image, $context ) {
    if ( str_contains( $image, 'hero-banner' ) ) {
        return false; // no loading="lazy"
    }
    return $value;
}, 10, 3 );
```

### CLS (Cumulative Layout Shift)  { clearTimeout(id); id = setTimeout(() => fn(...args), ms); };
}
window.addEventListener('scroll', debounce(handleScroll), { passive: true });

// Break long tasks with yield
async function processItems(items) {
    for (const item of items) {
        doWork(item);
        if (performance.now() - start > 50) {
            await new Promise(r => setTimeout(r, 0)); // yield to main thread
        }
    }
}
```

Keep DOM under 1500 nodes. Audit with: `document.querySelectorAll('*').length`.

---

## 2. Mobile-First WordPress Design

### Breakpoint Strategy

```css
/* Mobile-first: base styles are mobile (320px+) */
/* Small phones handled by fluid units, no breakpoint needed */

@media (min-width: 480px)  { /* Large phones */  }
@media (min-width: 768px)  { /* Tablets */        }
@media (min-width: 1024px) { /* Small desktop */  }
@media (min-width: 1280px) { /* Large desktop */  }
```

### Touch Targets and Viewport

```css
/* Minimum 44x44px touch targets — WCAG 2.5.8 */
button, a, input, select, textarea {
    min-height: 44px;
    min-width: 44px;
}

/* Prevent iOS zoom on input focus */
input, select, textarea {
    font-size: 16px; /* >= 16px prevents auto-zoom */
}
```

```html

```

### Mobile Menu Patterns

Hamburger menu for primary nav on mobile. Place critical actions in thumb zone (bottom 40% of screen).

```css
/* Bottom nav for high-frequency actions */
.mobile-bottom-nav {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    height: 56px;
    display: flex;
    justify-content: space-around;
    align-items: center;
    background: var(--wp--preset--color--base);
    box-shadow: 0 -1px 3px rgb(0 0 0 / 0.1);
    z-index: 100;
    padding-bottom: env(safe-area-inset-bottom);
}

@media (min-width: 768px) {
    .mobile-bottom-nav { display: none; }
}
```

---

## 3. Typography System

### Modular Scale (ratio 1.25 — Major Third)

```css
:root {
    --step--2: clamp(0.64rem, 0.58rem + 0.28vw, 0.80rem);
    --step--1: clamp(0.80rem, 0.73rem + 0.35vw, 1.00rem);
    --step-0:  clamp(1.00rem, 0.91rem + 0.43vw, 1.25rem);  /* body */
    --step-1:  clamp(1.25rem, 1.14rem + 0.54vw, 1.56rem);  /* h4 */
    --step-2:  clamp(1.56rem, 1.43rem + 0.68vw, 1.95rem);  /* h3 */
    --step-3:  clamp(1.95rem, 1.78rem + 0.85vw, 2.44rem);  /* h2 */
    --step-4:  clamp(2.44rem, 2.23rem + 1.07vw, 3.05rem);  /* h1 */
}
```

### WordPress theme.json Typography

```json
{
    "settings": {
        "typography": {
            "fluid": true,
            "fontSizes": [
                { "slug": "small",  "size": "clamp(0.80rem, 0.73rem + 0.35vw, 1.00rem)", "name": "Small" },
                { "slug": "medium", "size": "clamp(1.00rem, 0.91rem + 0.43vw, 1.25rem)", "name": "Medium" },
                { "slug": "large",  "size": "clamp(1.56rem, 1.43rem + 0.68vw, 1.95rem)", "name": "Large" },
                { "slug": "x-large","size": "clamp(2.44rem, 2.23rem + 1.07vw, 3.05rem)", "name": "Extra Large" }
            ],
            "fontFamilies": [
                { "slug": "brand", "fontFamily": "'Brand', system-ui, sans-serif", "name": "Brand" },
                { "slug": "mono",  "fontFamily": "'JetBrains Mono', monospace",    "name": "Mono"  }
            ]
        }
    }
}
```

### Line Length and Spacing

```css
/* Optimal measure: 45-75 characters */
.entry-content p,
.entry-content li {
    max-width: 65ch;
    line-height: 1.6;
}

h1, h2, h3 { line-height: 1.2; }
h4, h5, h6 { line-height: 1.3; }
```

### Font Loading Strategy

```php
// Preload critical fonts in 
add_action( 'wp_head', function() {
    echo '' . "\n";
}, 1 );
```

---

## 4. Color System

### theme.json Color Palette

```json
{
    "settings": {
        "color": {
            "palette": [
                { "slug": "primary",    "color": "#1a56db", "name": "Primary"    },
                { "slug": "secondary",  "color": "#6b7280", "name": "Secondary"  },
                { "slug": "accent",     "color": "#f59e0b", "name": "Accent"     },
                { "slug": "base",       "color": "#ffffff", "name": "Base"       },
                { "slug": "contrast",   "color": "#111827", "name": "Contrast"   },
                { "slug": "success",    "color": "#059669", "name": "Success"    },
                { "slug": "warning",    "color": "#d97706", "name": "Warning"    },
                { "slug": "error",      "color": "#dc2626", "name": "Error"      }
            ]
        }
    }
}
```

### Semantic Token Usage

```css
/* Use WordPress preset variables everywhere */
.btn-primary {
    background: var(--wp--preset--color--primary);
    color: var(--wp--preset--color--base);
}

.alert-error {
    border-left: 4px solid var(--wp--preset--color--error);
    background: color-mix(in srgb, var(--wp--preset--color--error) 8%, white);
}
```

### WCAG AA Contrast (4.5:1 text, 3:1 large text/UI)

```css
/* Dark mode via media query */
@media (prefers-color-scheme: dark) {
    :root {
        --wp--preset--color--base: #111827;
        --wp--preset--color--contrast: #f9fafb;
    }
}
```

Always verify contrast ratios. Minimum 4.5:1 for body text, 3:1 for large text (18px+ or 14px bold) and UI components.

---

## 5. Navigation UX

### Breadcrumbs

```php
// Output semantic breadcrumbs (works with Yoast, Rank Math, or custom)
function zentratec_breadcrumbs() {
    if ( function_exists('rank_math_the_breadcrumbs') ) {
        rank_math_the_breadcrumbs();
    } elseif ( function_exists('yoast_breadcrumb') ) {
        yoast_breadcrumb('', '');
    }
}
```

### Pagination: Prefer Numbered Over Infinite Scroll

Infinite scroll breaks footer access and disables back-button history. Use numbered pagination or "Load More" with URL state.

```php
// Accessible numbered pagination
the_posts_pagination([
    'mid_size'  => 2,
    'prev_text' => '&laquo;',
    'next_text' => '&raquo;',
]);
```

### Back-to-Top

```css
.back-to-top {
    position: fixed;
    bottom: 2rem;
    right: 2rem;
    opacity: 0;
    transition: opacity 200ms ease;
    pointer-events: none;
}
.back-to-top.visible {
    opacity: 1;
    pointer-events: auto;
}
```

```js
const btn = document.querySelector('.back-to-top');
const observer = new IntersectionObserver(([e]) => {
    btn.classList.toggle('visible', !e.isIntersecting);
}, { rootMargin: '-300px 0px 0px 0px' });
observer.observe(document.querySelector('header'));
```

---

## 6. Page Builder UX

### Section / Row / Column Hierarchy

All builders (Tatsu, Elementor, WPBakery) share this pattern. Enforce consistent spacing at each level.

```css
/* Consistent section spacing */
.tatsu-section,
.elementor-section,
.vc_section {
    padding-block: var(--section-spacing, clamp(3rem, 6vw, 6rem));
}

/* Content width management */
.tatsu-row,
.elementor-container,
.vc_row {
    max-width: var(--content-width, 1200px);
    margin-inline: auto;
    padding-inline: clamp(1rem, 3vw, 2rem);
}
```

### Builder CSS Override Pattern

Use specificity, not `!important`. Target the builder's own wrapper classes.

```css
/* Override builder defaults cleanly with specificity */
body .tatsu-section .tatsu-column .tatsu-text-block p {
    font-size: var(--step-0);
    line-height: 1.6;
    max-width: 65ch;
}

/* For Elementor: use the widget wrapper */
.elementor-widget-text-editor .elementor-widget-container p {
    font-size: var(--step-0);
}
```

---

## 7. Image Optimization UX

### Responsive Images with Art Direction

```html

    
    
    

```

### WordPress Lazy Loading Rules

- Above-fold images: NO `loading="lazy"`, YES `fetchpriority="high"`
- Below-fold images: YES `loading="lazy"`, YES `decoding="async"`
- Background images: use `content-visibility: auto` on the container

### Placeholder Strategy (LQIP)

```php
// Generate inline low-quality placeholder
function get_lqip_style( $attachment_id ) {
    $thumb = wp_get_attachment_image_url( $attachment_id, [32, 32] );
    if ( ! $thumb ) return '';
    return sprintf(
        'background: url(%s) center/cover no-repeat; filter: blur(20px);',
        esc_url( $thumb )
    );
}
```

```html
">
    

```

---

## 8. Form UX

### Inline Validation and Smart Defaults

```html

    
        Email address
        
        
            Enter a valid email address
        
    

```

```js
// Inline validation on blur, not on input
document.querySelectorAll('input[required]').forEach(input => {
    input.addEventListener('blur', () => {
        const error = document.getElementById(input.getAttribute('aria-describedby'));
        if (!error) return;
        const invalid = !input.validity.valid;
        error.hidden = !invalid;
        input.setAttribute('aria-invalid', String(invalid));
    });
});
```

### Multi-Step Forms

```css
/* Progress indicator */
.form-steps {
    display: flex;
    gap: 0.5rem;
    counter-reset: step;
}
.form-step { counter-increment: step; }
.form-step::before {
    content: counter(step);
    display: grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    background: var(--wp--preset--color--secondary);
    color: white;
    font-weight: 700;
}
.form-step[aria-current="step"]::before {
    background: var(--wp--preset--color--primary);
}
```

### Autocomplete Attributes Checklist

Always set: `name`, `email`, `tel`, `street-address`, `postal-code`, `country`, `cc-number`, `cc-exp`, `cc-csc`, `given-name`, `family-name`, `organization`.

---

## 9. Loading States

### Skeleton Screens Over Spinners

Skeletons preserve layout and feel faster than spinners. Use them for content regions.

```css
.skeleton {
    background: linear-gradient(90deg,
        var(--wp--preset--color--base) 25%,
        color-mix(in srgb, var(--wp--preset--color--contrast) 8%, transparent) 50%,
        var(--wp--preset--color--base) 75%);
    background-size: 200% 100%;
    animation: shimmer 1.5s infinite;
    border-radius: 4px;
}
@keyframes shimmer { to { background-position: -200% 0; } }

.skeleton-text { height: 1em; margin-bottom: 0.75em; }
.skeleton-text:last-child { width: 60%; }
.skeleton-image { aspect-ratio: 16 / 9; }
```

### Transition Timing

- Micro-interactions (hover, focus): 150ms
- Content transitions (modals, accordions): 250ms
- Page-level transitions: 300ms
- Easing: `cubic-bezier(0.4, 0, 0.2, 1)` for standard, `cubic-bezier(0, 0, 0.2, 1)` for deceleration

### WordPress AJAX Pattern

```js
async function wpAjaxLoad(action, container) {
    container.setAttribute('aria-busy', 'true');
    container.innerHTML = ''.repeat(3);
    try {
        const res = await fetch(wpApiSettings.root + action, {
            headers: { 'X-WP-Nonce': wpApiSettings.nonce }
        });
        if (!res.ok) throw new Error(res.statusText);
        container.innerHTML = await res.text();
    } catch (err) {
        container.innerHTML = 'Failed to load. Retry';
    } finally {
        container.removeAttribute('aria-busy');
    }
}
```

---

## 10. Error States

### 404 Page Requirements

Every 404 must include: (1) clear "not found" message, (2) search form, (3) popular/recent content links, (4) link back to homepage.

```php
// 404.php template
get_header(); ?>

    
    
    
    
    
     5, 'orderby' => 'comment_count']);
    while ($popular->have_posts()) : $popular->the_post(); ?>
        ">
    
    
    ">

 5]);
    if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
        $stale = get_option('external_data_fallback', []);
        return $stale; // serve stale data rather than fail
    }

    $data = json_decode(wp_remote_retrieve_body($response), true);
    set_transient('external_data', $data, HOUR_IN_SECONDS);
    update_option('external_data_fallback', $data);
    return $data;
}
```

---

## 11. WordPress Admin UX

### Custom Settings Pages

Match WordPress admin styling. Use the Settings API.

```php
add_action('admin_menu', function() {
    add_options_page('Brand Settings', 'Brand', 'manage_options', 'brand-settings', 'render_brand_settings');
});

add_action('admin_init', function() {
    register_setting('brand_group', 'brand_primary_color', ['sanitize_callback' => 'sanitize_hex_color']);
    add_settings_section('brand_colors', 'Color Settings', null, 'brand-settings');
    add_settings_field('primary_color', 'Primary Color', function() {
        $val = get_option('brand_primary_color', '#1a56db');
        echo '';
    }, 'brand-settings', 'brand_colors');
});

function render_brand_settings() {
    echo 'Brand Settings';
    settings_fields('brand_group');
    do_settings_sections('brand-settings');
    submit_button();
    echo '';
}
```

### Admin Notices

```php
// Dismissible success notice
add_action('admin_notices', function() {
    if (!get_transient('brand_saved')) return;
    delete_transient('brand_saved');
    echo 'Settings saved.';
});
```

Use `notice-success`, `notice-error`, `notice-warning`, `notice-info`. Always add `is-dismissible` for non-critical messages.

---

## 12. Performance UX Checklist

Run this checklist before any page is considered complete.

| Metric               | Target          | How to Verify                          |
|----------------------|-----------------|----------------------------------------|
| LCP                  | ` in head   |

### Quick Audit Script

```js
// Paste in DevTools console
(() => {
    const imgs = document.querySelectorAll('img:not([width]), img:not([height])');
    const bigDOM = document.querySelectorAll('*').length;
    const noAlt = document.querySelectorAll('img:not([alt])');
    const smallTargets = [...document.querySelectorAll('a, button')].filter(el => {
        const r = el.getBoundingClientRect();
        return r.width < 44 || r.height < 44;
    });
    console.table({
        'Images missing dimensions': imgs.length,
        'DOM nodes': bigDOM,
        'Images missing alt': noAlt.length,
        'Touch targets < 44px': smallTargets.length,
    });
})();
```

---

## Enforcement Rules

When reviewing WordPress code, flag violations of these standards:

1. **No dimensions on images** -- always require width/height attributes
2. **lazy loading on above-fold images** -- first viewport image must not be lazy
3. **Touch targets below 44px** -- buttons and links must meet minimum size
4. **Missing autocomplete attributes on forms** -- all identity/payment fields need them
5. **Spinner instead of skeleton** -- prefer skeleton screens for content regions
6. **Infinite scroll without URL state** -- pagination must preserve browser history
7. **!important in builder overrides** -- use specificity instead
8. **Hardcoded colors instead of CSS custom properties** -- use semantic tokens
9. **Missing error states** -- every async operation needs failure handling
10. **No font-display on @font-face** -- always set font-display: swap

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [xonack](https://github.com/xonack)
- **Source:** [xonack/wp-ux-design-claude-skill](https://github.com/xonack/wp-ux-design-claude-skill)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-xonack-wp-ux-design-claude-skill-wp-ux-design
- Seller: https://agentstack.voostack.com/s/xonack
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
