AgentStack
SKILL verified MIT Self-run

Wp Ux Design

skill-xonack-wp-ux-design-claude-skill-wp-ux-design · by xonack

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.

No reviews yet
0 installs
2 views
0.0% view→install

Install

$ agentstack add skill-xonack-wp-ux-design-claude-skill-wp-ux-design

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Wp Ux Design? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

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

/* 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 */
}

Mobile Menu Patterns

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

/* 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)

: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

{
    "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

/* 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

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

4. Color System

theme.json Color Palette

{
    "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

/* 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)

/* 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

// 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.

// Accessible numbered pagination
the_posts_pagination([
    'mid_size'  => 2,
    'prev_text' => '«',
    'next_text' => '»',
]);

Back-to-Top

.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;
}
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.

/* 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.

/* 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


    
    
    

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)

// 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 )
    );
}
">
    

8. Form UX

Inline Validation and Smart Defaults


    
        Email address
        
        
            Enter a valid email address
        
    
// 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

/* 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.

.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

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.

// 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.

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

// 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

// 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.

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

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.