From 85c68a4fe9b0feb66ff4d09d150004255ebe6ac1 Mon Sep 17 00:00:00 2001 From: Jasper Frumau Date: Mon, 22 Jun 2026 09:15:43 +0700 Subject: [PATCH 1/3] Update Vibe Configuration --- .vibe/config.toml | 2 +- .vibe/prompts/vibe.md | 706 ------------------------------------------ 2 files changed, 1 insertion(+), 707 deletions(-) delete mode 100644 .vibe/prompts/vibe.md diff --git a/.vibe/config.toml b/.vibe/config.toml index bd547f0..9d9440d 100644 --- a/.vibe/config.toml +++ b/.vibe/config.toml @@ -6,7 +6,7 @@ auto_compact_threshold = 200000 context_warnings = false textual_theme = "catppuccin-mocha" instructions = "" -system_prompt_id = "vibe" +system_prompt_id = "cli" include_commit_signature = true include_model_info = true include_project_context = true diff --git a/.vibe/prompts/vibe.md b/.vibe/prompts/vibe.md deleted file mode 100644 index c995483..0000000 --- a/.vibe/prompts/vibe.md +++ /dev/null @@ -1,706 +0,0 @@ -# Elayne Theme Development Guide - -This file provides development guidelines for the Elayne WordPress block theme. - -## Important Git Commit Guidelines - -**NO Mistral Vibe Attribution in Any Commits** -- Do NOT include Mistral Vibe attribution in any commits -- Do NOT add "Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe " attribution -- Keep all commits professional and attribution-free -- This applies to ALL files and directories in the entire repository -- Do atomic commits making sure files are added individually or in groups with specific messages -- Follow standard git commit message format - -**Changelog and Readme Updates** -- When updating `CHANGELOG.md` or `readme.txt`, do NOT describe changes as "Changed" unless the file already existed in the main branch -- New changelog entries are ADDITIONS, not changes to existing files - -## Efficiency -- Avoid reading entire files when only a specific section is needed -- Use `Grep` to locate relevant code before reading -- Prefer targeted reads with `offset` and `limit` parameters over full file reads - -## Project Overview - -Elayne is a premium WordPress block theme for professional business websites: -- **Architecture**: Pure block theme (no build tools, no npm/composer) -- **WordPress Version**: 6.6+ required -- **PHP Version**: 8.0+ required -- **Theme Type**: Full Site Editing (FSE) block theme -- **Target Audience**: Professional businesses, spas, real estate, and service industries - -## Theme Architecture - -### Pure Block Theme Structure -- **No build process**: Direct PHP, HTML, and vanilla JavaScript -- **theme.json**: Single source of truth for styles, colors, typography, spacing -- **HTML templates**: Block markup in `templates/` directory -- **PHP patterns**: Reusable block patterns in `patterns/` directory -- **Block extensions**: Vanilla JavaScript in `assets/js/block-extensions/` - -### Directory Structure -``` -elayne/ -├── assets/ -│ ├── fonts/ # Variable fonts (Mona Sans, Open Sans, Bitter) -│ └── js/ -│ └── block-extensions/ # Vanilla JS extensions for core blocks -├── inc/ -│ └── block-extensions.php # PHP handlers for block extensions -├── languages/ # Translation files (text domain: 'elayne') -├── parts/ # Template parts (header.html, footer.html) -├── patterns/ # PHP block patterns -├── templates/ # HTML templates (index, single, page) -├── functions.php # Theme setup and pattern categories -├── style.css # Theme metadata (no actual styles) -└── theme.json # Global styles, settings, colors, typography -``` - -## Development Workflow - -### Local Development with Trellis VM -The demo site uses **Trellis VM** (Lima-based, NOT Vagrant). - -- **Protocol**: HTTP — `http://demo.imagewize.test/` (NOT `https://`) -- **File sync**: Automatic real-time sync via Lima — no manual rsync needed -- **Common issue**: Changes not appearing → WordPress cache, not file sync - -### WooCommerce Store Subsite - -WooCommerce runs on a **subsite at `/store/`**. All shop URLs are prefixed: - -| Page | URL | -|---|---| -| Shop (product catalog) | `http://demo.imagewize.test/store/shop/` | -| Product category | `http://demo.imagewize.test/store/product-category/{slug}/` | -| Single product | `http://demo.imagewize.test/store/product/{slug}/` | - -**Block theme template hierarchy** (`templates/` directory): -- `archive-product.html` → shop page + fallback for all product archives -- `taxonomy-product_cat.html` → category archive pages (different filter set, no category filter) -- `single-product.html` → single product pages - -**WooCommerce filter blocks** (WooCommerce 10.7+): -- Use `woocommerce/product-filter-taxonomy` with `{"taxonomy":"product_cat"}` for category filtering — `product-filter-category` does NOT exist -- Use `woocommerce/product-filter-attribute` **without** `attributeId` for distributable templates — renders as an unconfigured placeholder the client configures via Site Editor (Ollie pattern; no hardcoded IDs). Only include `attributeId` when building demo-specific templates. - -**Demo store attribute IDs** (May 2026 — do NOT hardcode in distributable templates): `1` = Leather Colour, `2` = Style, `3` = Features - -**Clear cache** (rarely needed — see mu-plugin note below): -```bash -cd ~/code/imagewize.com/trellis -trellis vm shell --workdir /srv/www/demo.imagewize.com/current -- wp cache flush --path=web/wp -``` - -**mu-plugin active:** `demo/web/app/mu-plugins/fse-dev-mode.php` hooks `pre_get_block_template` (fires before WordPress queries the DB) and returns the filesystem `WP_Block_Template` via `get_block_file_template()` when `WP_ENV=development`. This bypasses `wp_template`/`wp_template_part` DB overrides entirely — template and template-part file edits appear on plain refresh with no WP-CLI required. Templates with no matching filesystem file (WooCommerce archives, plugin templates) fall through to the DB normally. - -**Rebuild demo subsites from patterns:** After modifying pattern PHP files, you **must** run `demo/scripts/rebuild-demo-subsite.php` to rebuild demo site pages from the latest pattern files before testing with Playwright. This is vital for testing pattern changes locally without manual reloading. The rebuild script captures each pattern within the live WP context and overwrites post_content — identical to a fresh block-editor insert. Run it from the VM: -```bash -# Rebuild a single subsite (dev environment) -cd /srv/www/demo.imagewize.com/current -wp --path=web/wp --url=demo.imagewize.test/kafe/ eval-file scripts/rebuild-demo-subsite.php kafe - -# Dry run first to see what would change -WP_REBUILD_DRY_RUN=1 wp --path=web/wp --url=demo.imagewize.test/kafe/ eval-file scripts/rebuild-demo-subsite.php kafe - -# Available subsites: main, legal, kafe, nail-salon, plumbing, store, spa -``` -**Workflow:** Modify pattern → rebuild with `rebuild-demo-subsite.php` → flush cache → test with Playwright (`test.js`). Run this locally often — it saves time by avoiding manual page reloads in the editor. - -### WordPress Development Mode -`WP_DEVELOPMENT_MODE=theme` is set in `config/environments/development.php` — bypasses theme.json/style transients on every request. Combined with the `fse-dev-mode.php` mu-plugin, `wp cache flush` is no longer needed for normal theme development. The only remaining manual step is a hard refresh (Cmd+Shift+R) in the Site Editor after theme.json changes, to update React's client-side state. - -Disable `WP_DEVELOPMENT_MODE` in production for optimal performance. - -### Style Variation Caching -WordPress aggressively caches compiled global styles. When `theme.json` or `styles/*.json` changes don't appear: - -1. **Flush cache** (often enough with `WP_DEVELOPMENT_MODE=theme`) -2. **Switch style variations** in the Site Editor (`Styles → Browse styles`): switch away and back. Forces recompile. -3. **Nuclear option**: Delete the `wp_global_styles` custom post type and flush cache. - -### Pattern URL Behavior -`get_template_directory_uri()` returns environment-specific URLs that get hardcoded into the database. - -**Always run search-replace when deploying content to production:** -```bash -ssh web@demo.imagewize.com "cd /srv/www/demo.imagewize.com/current && \ - wp search-replace 'http://demo.imagewize.test' 'https://demo.imagewize.com' \ - --all-tables --precise --path=web/wp && wp cache flush --path=web/wp" -``` - -## PHP Code Quality (functions.php) - -Always run phpcs/phpcbf **from the theme directory** so `phpcs.xml` (WordPress standards) is picked up automatically. Using the wrong working directory silently applies a different standard and can introduce hundreds of new violations. - -```bash -# Check -cd demo/web/app/themes/elayne && vendor/bin/phpcs functions.php - -# Auto-fix (run check again after to confirm clean) -cd demo/web/app/themes/elayne && vendor/bin/phpcbf functions.php -``` - -**WordPress coding standard rules for functions.php** (common traps): -- Use `array()` — **never** `[]` short array syntax -- Indent with **tabs**, not spaces -- Multi-line function calls: opening `(` must be last on the line, each argument on its own line, closing `)` on its own line -- Array alignment: values must align with the longest key in the array - -## Design System - -### Color Palette (theme.json) -- **Brand**: `primary` (teal), `primary-accent` (light teal), `primary-dark` (dark teal) -- **Contrast**: `main` (dark gray), `main-accent` (medium gray) -- **Base**: `base` (white), `secondary` (light gray), `tertiary` (very light gray) -- **Borders**: `border-light`, `border-dark` - -**Important**: All design tokens are defined in `theme.json`. Never hardcode colors, sizes, or spacing in patterns. - -### Typography -- **Mona Sans** (variable 300-900) — headings -- **Open Sans** (variable 300-800) — body text fallback -- **Bitter** (variable 100-900, serif) — optional serif - -**Fluid Font Sizes**: `xx-small` → `x-small` → `small` → `base` → `medium` → `large` → `x-large` → `xx-large` - -**Actual font-size values (critical — prevents oversized headings):** -| Slug | Max value | Use for | -|---|---|---| -| `x-small` | 0.95rem | Labels, badges, captions | -| `small` | 1.05rem | Small body, buttons | -| `base` | 1.165rem | Body text | -| `medium` | 1.65rem | Lead text, stat labels | -| `large` | 2.75rem | H1 on dark hero, stat numbers | -| `x-large` | 3.5rem | Display H1 only | -| `xx-large` | 4.39rem | Rarely used — very large display only | - -### Spacing Scale -`2-x-small`, `x-small`, `small`, `medium`, `large`, `x-large`, `xx-large`, `xxx-large` (all use clamp() for responsive scaling) -— ⚠️ `xx-small` does NOT exist. Use `2-x-small` or `x-small`. - -**Actual spacing values (critical — prevents oversized pills/badges):** -| Slug | Value | -|---|---| -| `2-x-small` | clamp(0.25rem → 0.5rem) ~4–8px | -| `x-small` | clamp(0.375rem → 0.75rem) ~6–12px | -| `small` | clamp(0.5rem → 1rem) ~8–16px | -| `medium` | clamp(1.5rem → 2rem) ~24–32px ← LARGE, not "medium" | -| `large` | clamp(2rem → 3rem) ~32–48px | -| `x-large` | clamp(3rem → 5rem) ~48–80px | - -**Pill/badge padding rule:** Always use `x-small` (vertical) + `small` (horizontal). Never `medium` — that is ~28px per side and will make any pill grotesquely wide. - -**Pill/badge shrink-wrap rule (CRITICAL — prevents full-column-width pills):** WordPress `is-layout-flow` columns are internally `flex-direction: column` flex containers. Any child element is a flex item — CSS blockifies it to `display: block` regardless of any `display: inline-block` or `display: inline-flex` rule or inline style. The default `align-items: normal` acts as `stretch`, making every child span the full column width. To make a pill/badge shrink-wrap inside a `wp:column`, add `align-self: flex-start` and `width: fit-content` to its **CSS rule** — NOT as an inline style. - -```css -/* CORRECT — pill/badge inside a wp:column */ -.my-context .my-pill { - align-self: flex-start; /* prevents stretch in WP's flex-direction:column column */ - width: fit-content; -} -``` - -`is-style-status-pill` works in the editorial header because the header uses a `flex-direction: row` container — in row-flex the cross-axis is vertical, so width is content-driven naturally. If the same pill were inside a `wp:column`, it would need this fix too. Never chase `display: inline-*` for shrink-wrapping inside WP columns — it doesn't work. - -### WooCommerce Implementation -- **Three-tier strategy:** Tier 1 = Use WooCommerce plugin patterns as-is (EXEMPT from Elayne rules), Tier 2 = Style with theme CSS, Tier 3 = Custom Elayne patterns only if needed -- **Plugin patterns:** Use `demo/web/app/plugins/woocommerce/patterns/*.php` directly via `` -- **Naming:** Use `woo-` prefix for WooCommerce patterns (e.g., `woo-cart.php`) -- **Categories:** Use only `elayne/woocommerce` (registered in functions.php) -- **Colors:** Use registered palette (`primary`, `main`, `base`, `tertiary`, `primary-accent`) - **NEVER use charcoal or cream** -- **Single product:** Use product blocks directly - **NEVER wrap in `woocommerce/product-template`** -- **Archive:** `product-collection` handles own pagination - **NEVER use standalone `query-pagination`** -- **Buttons:** Root-level attributes first (`className` before `style`) -- **Full-width:** Outer `alignfull` group must use `"layout":{"type":"default"}` - -## Pattern Development - -### Pattern Structure -```php - - -``` - -**Custom Pattern Categories** (registered in functions.php): -- `elayne/hero`, `elayne/features`, `elayne/call-to-action` -- `elayne/testimonial`, `elayne/team`, `elayne/statistics` -- `elayne/contact`, `elayne/posts` -- `elayne/card-simple` (18rem), `elayne/card-extended` (19rem), `elayne/card-profiles` (20rem) - -### Creating New Patterns -1. Create PHP file in `patterns/` — naming: `category-descriptive-name.php` -2. Add header comment: Title, Slug, Categories, Description, Keywords, Viewport Width, Grid Config -3. Use semantic variables: `var:preset|color|primary`, `var:preset|spacing|medium` -4. Register slug as: `elayne/pattern-name` -5. **Wrap ALL user-facing text** in `` — every heading, paragraph, button label, non-empty alt text (WP.org requirement) -6. **Use `get_template_directory_uri()`** for all image `src` — never hardcode URLs -7. Test in block editor inserter - -### Critical Pattern Rules - -| Rule | Quick summary | -|---|---| -| **Native blocks** | NEVER use `wp:html` — always use `wp:list`, `wp:group`, `wp:heading`, etc. | -| **HTML comments** | NEVER add `` between `
` tags and block comments — causes validation failure | -| **Whitespace between blocks** | NEVER add tabs, newlines, or spaces between an opening/closing `
` and the adjacent `` / `` comment — block serialization is whitespace-strict | -| **Block attributes** | `backgroundColor`, `layout`, `align` are root-level — NEVER nest inside `style` object | -| **Full-width layout** | Outer `alignfull` group: ALWAYS `"layout":{"type":"default"}`; inner groups use `"constrained"` | -| **Page template** | `post-content` block must use `"layout":{"type":"constrained"}` — NOT `"default"` | -| **Icons** | NEVER use emoji — always use SVG icons stored in `patterns/images/` | -| **Images** | NEVER hardcode media IDs; ALWAYS use `get_template_directory_uri()` wrapped in `esc_url()` | -| **External images** | NEVER use hardcoded external URLs (e.g. `http://demo.imagewize.test/...`) — WP.org rejection | -| **Image block** | `is-resized` class required when width/height set; `align` comes after width/height in JSON | -| **Image block — theme SVGs** | NEVER add `width`/`height` attributes to `` inside `wp:image` for theme-bundled SVGs — no media ID means WP can't validate dimensions and throws a block validation error. Use `` only. | -| **Translation strings** | ALL user-facing text in patterns MUST use `esc_html_e()` / `esc_attr__()` with `'elayne'` domain | -| **Translation alt text** | ALL alt attributes MUST use `esc_attr__()` — NEVER bare text | -| **WP-CLI patterns** | Use `` — NEVER `php -r 'include ...'` | -| **Font sizes** | NEVER hardcode `font-size: 10px` — use semantic variables (`var:preset|font-size|*`) | -| **Spacer blocks** | NEVER use `wp:spacer` — use `blockGap` on parent containers | -| **Emails** | NEVER use custom domains — use `example@example.com` only (WP.org requirement) | -| **Button fontSize** | NEVER use root-level `"fontSize":"base"` on `wp:button` — use `"style":{"typography":{"fontSize":"var:preset|font-size|base"}}` | -| **Button attribute order** | NEVER put `className` after `style` — root-level attributes first | -| **Cover block minHeight** | NEVER use `style.dimensions.minHeight` without root `minHeight` — causes validation failure | -| **overflow:hidden** | NEVER use as inline style on groups — use className with CSS instead | -| **opacity** | NEVER use as inline style — use className with CSS instead | -| **Custom block types** | NEVER use `register_block_type()` in a theme — WP.org plugin-territory violation. Use the `render_block` filter on `core/group` with a specific `className` instead (same pattern as the ticker). | - -> **Full details with code examples**: `docs/elayne/PATTERN-GUIDELINES.md` - -### Block HTML Validation Rules (Critical) - -WordPress validates blocks by comparing the `save` function output against the stored HTML in the pattern. Mismatches cause `Block validation failed` errors in the editor console. Three classes of error are common in Elayne patterns: - -**1. fontSize / fontFamily as block attributes → must use CSS classes, not inline styles** - -When `fontSize` or `fontFamily` appear as ROOT-level block attributes (outside `"style":{...}`), WordPress's save function generates CSS classes — NOT inline `style` values. The HTML must match. - -| Block JSON | Required HTML class | Wrong HTML (causes error) | -|---|---|---| -| `"fontSize":"x-large"` | `has-x-large-font-size` | `style="font-size:var(--wp--preset--font-size--x-large)"` | -| `"fontFamily":"var:preset\|font-family\|heading"` | `has-var-preset-font-family-heading-font-family` | `style="font-family:var(--wp--preset--font-family--heading)"` | - -This is different from `"style":{"typography":{"fontSize":"var:preset|font-size|large"}}` which intentionally produces an inline style. - -**2. blockGap and WordPress 6.6+ inline gap behavior** - -WordPress 6.6+ **stopped** outputting inline `gap` for most layouts. The `blockGap` attribute in JSON is now handled by WordPress's layout CSS system (`--wp--style--block-gap`) for constrained/default layouts. - -| Block type | Layout | HTML gap requirement | -|---|---|---| -| `core/group` | `flex` | **Must have** `style="gap:..."` — flex layout still needs inline gap | -| `core/group` | `constrained` or `default` | **Must NOT have** `gap` inline — WP layout CSS handles it | -| `core/columns` | any | **Must NEVER have** `gap` inline — block CSS handles column gap | - -```html - - -
- - - -
- - - -
-``` - -**3. metadata.name — only on the root block** - -The `"metadata":{"name":"...","patternName":"..."}` attributes identify a block as the root of a named pattern. They should only appear on the OUTERMOST block of a standalone pattern file. Adding `metadata` to inner/nested blocks causes those blocks to appear as named patterns in the editor and can confuse WordPress's pattern tracking. - -```html - - ← nested inside another block - - - -
← this IS the first block in the .php file -``` - -> **Pattern Validation** uses a two-pass approach: (1) Gutenberg structural validator — `cd demo && wp pattern validate web/wp/wp-content/themes/elayne/patterns/*.php --fix`; (2) Elayne compliance checker — `php scripts/elayne/pattern-check/class-patterncompliancechecker.php demo/web/app/themes/elayne/patterns/*.php`. Always run Pass 1 first. - -### WooCommerce Pattern Rules - -**Note:** WooCommerce plugin patterns (`woocommerce/patterns/*.php`) are **EXEMPT** from Elayne's strict compliance rules per CLAUDE.md. These rules apply only to **theme-specific patterns** that use WooCommerce blocks. - -| Rule | Quick summary | -|---|---| -| **product-title in template** | NEVER use `woocommerce/product-title` inside `product-template` — use `post-title` with `__woocommerceNamespace` | -| **Native WC blocks** | NEVER add `__woocommerceNamespace` to `product-image`, `product-price`, `product-rating`, `product-button`, `product-sale-badge` | -| **product-collection query** | ALWAYS include full `"query":{...}` metadata | -| **product-collection wrapper** | ALWAYS include `
` after opening block comment | -| **product-collection layout** | NEVER use both `layout` and `displayLayout` — use only `displayLayout` for WooCommerce blocks | - -### Grid Layouts - -- **ALWAYS use `minimumColumnWidth` grid** for 3+ column layouts (true 3→2→1 responsive) -- **NEVER use `wp:columns`** for 3-column patterns — skips 2-column tablet breakpoint -- **NEVER use fixed `columnCount`** — ignores viewport size -- Use `rem` units: `18rem` simple cards, `19rem` complex cards, `20rem` profiles, `28-29rem` text-heavy - -```html - - -``` - -> **Full details**: `docs/elayne/GRID-LAYOUT-STANDARDS.md` - -### Spacing & BlockGap - -- **NO spacer blocks** — use `blockGap` on parent containers -- **NO manual margins** on headings/paragraphs — let parent `blockGap` control spacing -- **Full-width sections** MUST reset margins: `"margin":{"top":"0","bottom":"0"}` (no units) -- **Horizontal padding**: always on outer container — `left/right: var:preset|spacing|medium` -- Semantic scale: `small` (tight grouping) → `medium` → `large` → `x-large` (major section breaks) - -> **Full details**: `docs/elayne/DESIGN-REFACTOR.md` - -### Translation Readiness (CRITICAL — WP.org Review Requirement) - -**Every user-facing string in every pattern PHP file MUST be wrapped in a translation function.** Unwrapped strings cause WP.org theme review rejection. - -| Content type | Function to use | Example | -|---|---|---| -| Text inside HTML tags | `esc_html_e( 'Text', 'elayne' )` | `

` | -| Text with inline HTML (``, `
`, ``) | `wp_kses_post( __( 'Text', 'elayne' ) )` | `

Elayne', 'elayne' ) ); ?>

` | -| Text in HTML attributes (alt, title, aria-label) | `esc_attr__( 'Text', 'elayne' )` | `alt=""` | - -**What to wrap:** all headings, paragraphs, list items, button labels, non-empty `alt` text, stat numbers, badge text, CTA text, testimonial quotes, names, job titles. - -**What NOT to wrap:** empty `alt=""` (decorative images), block comment JSON attributes, PHP expressions using `get_template_directory_uri()`. - -**Quick check before committing any pattern:** -```bash -# Find bare text between HTML tags that is NOT wrapped in a translation function -grep -n ">\s*[A-Z][^<]*\s*<" patterns/your-pattern.php -``` - -- Text domain: `'elayne'` -- Translation files in `/languages/` directory - -> ⚠️ **Unicode in PHP strings**: PHP single-quoted strings do NOT process `\u` escape sequences — `'–'` outputs the literal text `–`, not `–`. Always use the actual UTF-8 character (e.g. `'Mon–Fri · Sat'`) or a double-quoted string with `"\u{2013}"`. Never copy `\uXXXX` escapes from JavaScript into PHP single-quoted strings. - -### Border Radius Presets (WordPress 6.9+) - -Use `var:preset|border-radius|{slug}` in patterns — **not** hardcoded px values and **not** the non-existent `var:preset|border|radius`. - -**Elayne radius scale** (defined in `theme.json → settings.border.radiusSizes`): - -| Slug | Value | Used for | -|--------|----------|-------------------------------------| -| `sm` | 0.625rem | Buttons, small interactive elements | -| `md` | 0.75rem | Date boxes, inner card elements | -| `lg` | 1rem | Card outer containers | -| `pill` | 999px | Badges, tags, pill labels | - -**Border width**: No preset system exists — always hardcode `1px`. - -```php - -"style":{"border":{"radius":"var:preset|border-radius|lg","width":"1px"}} - - -"style":{"border":{"radius":"var:preset|border|radius","width":"var:preset|border|width"}} -``` - -> **Full details**: `docs/elayne/BORDER-PRESETS.md` - -### Valid Preset Slugs — Quick Reference - -**Spacing** (`var:preset|spacing|{slug}`): `2-x-small`, `x-small`, `small`, `medium`, `large`, `x-large`, `xx-large`, `xxx-large` -— ⚠️ `xx-small` does NOT exist. Use `2-x-small` or `x-small`. - -**Font sizes** (`var:preset|font-size|{slug}`): `xx-small`, `x-small`, `small`, `base`, `medium`, `large`, `x-large`, `xx-large` - -## Search/Replace Best Practices - -**Use unique, context-aware search patterns** for all search-and-replace operations: -- **Narrow patterns** by including surrounding code, comments, or unique identifiers (block slugs, function names, class names) -- **Avoid generic terms** like `"color"`, `"padding"`, or `"margin"` — these appear in multiple locations -- **Include block slugs or nearby PHP comments** to target only the intended occurrence -- **For `theme.json`**, include the full property path or parent keys in the search pattern - -**Example for Block Patterns** — instead of searching for `"alignfull"`, use: -```html - -``` - -**Example for `theme.json`** — instead of searching for `"primary"`, use the full context: -```json -"settings": { - "color": { - "palette": [ - { - "slug": "primary", - "color": "#0073aa" - } - ] - } -} -``` - -### Debugging Search/Replace Failures - -**Exact Matching Requirements**: Search/replace requires byte-for-byte matching. Even a single comma, space, or brace difference will cause failures. - -**Common Pitfalls** - -- **Brace count** *(most common)*: `"margin":{"top":"0"}}` vs. `"margin":{"top":"0"}}}` — deeply nested JSON has many closing braces; a single missing or extra `}` causes a 99%+ similarity fuzzy match but exact match failure. Always count closing braces carefully: - - `}` closes the innermost value object (e.g. `margin`) - - `}` closes the parent object (e.g. `spacing`) - - `}` closes the grandparent object (e.g. `style`) - - Then `,` before the next root-level attribute (e.g. `"backgroundColor"`) - -- **Commas**: `"margin":{"top":"0"}` vs. `"margin":{"top":"0"}},` - -- **Attribute order**: Block comment JSON attributes must appear in the exact order they exist in the file - -- **Quotation marks**: `"` vs. `"` or `'` - -- **Whitespace**: Tabs vs. spaces, trailing spaces, or `\r\n` vs. `\n` line endings - -- **Invisible characters**: Non-breaking spaces, BOM headers, or hidden formatting - -**Pre-Flight Checks (MANDATORY before any search/replace)** - -1. **Always grep first** — if grep doesn't find it, your search text is wrong: - ```bash - grep -Fn 'exact text to search' patterns/target-file.php - ``` - -2. **For long block comment lines**, grep for a shorter unique substring first, then read the line to verify brace counts: - ```bash - grep -n '"backgroundColor":"tertiary"' patterns/shop-overview-three-columns.php - ``` - -3. **Reveal hidden characters** if still failing: - ```bash - cat -A patterns/target-file.php | grep -n 'keyword' - ``` - -4. **Always commit before replacements** to enable easy rollback: - ```bash - git add patterns/target-file.php - git commit -m "Backup before search/replace" - ``` - -**Example: Brace Count Mismatch** - -File contains: -```html - -``` -A search pattern with `"margin":{"top":"0"}},"backgroundColor"` (missing one `}`) fails with ~99.8% similarity. The correct pattern needs three closing braces: `"margin":{"top":"0"}}},"backgroundColor"`. - -## Pattern Validation (four-pass) - -Always run all four validators. Pass 1 fixes structural issues that regex cannot catch. Pass 3 (sentinel) catches JS `save()` mismatches that Pass 1 cannot see. - -> **Pass 1 vs Pass 3 — critical distinction:** `wp pattern validate` (Pass 1) uses PHP `parse_blocks()` + `serialize_blocks()`. It does NOT run Gutenberg's JavaScript `save()` function. Issues only the JS serializer produces — `border-top-style:solid` auto-injection, `has-text-color` before `has-{preset}-font-size` class ordering, button link class ordering (`wp-block-button__link has-custom-font-size wp-element-button`), `backgroundColor:"base"` being dropped — will pass Pass 1 but fail in the browser. Pass 3 (sentinel) catches all of these. - -**Pass 1 — Gutenberg structural validator** (requires Trellis VM — database lives there): -```bash -# From project root - dry run -cd ~/code/imagewize.com - trellis vm shell --workdir /srv/www/demo.imagewize.com/current -- wp pattern validate web/wp/wp-content/themes/elayne/patterns/my-pattern.php - -# Auto-fix structural issues -cd ~/code/imagewize.com - trellis vm shell --workdir /srv/www/demo.imagewize.com/current -- wp pattern validate web/wp/wp-content/themes/elayne/patterns/my-pattern.php --fix - -# All patterns -cd ~/code/imagewize.com - trellis vm shell --workdir /srv/www/demo.imagewize.com/current -- wp pattern validate web/wp/wp-content/themes/elayne/patterns/ --fix - -# Using limactl directly (--workdir BEFORE VM name, no trailing --): -limactl shell --workdir /srv/www/demo.imagewize.com/current imagewize.com wp pattern validate web/wp/wp-content/themes/elayne/patterns/my-pattern.php --fix -``` - -**Pass 2 — pt-cli compliance checker** (from theme directory; no WordPress required): -```bash -# Run from theme directory -cd ~/code/imagewize.com/demo/web/app/themes/elayne - -# Check all patterns (via composer shortcut) -composer check - -# Or directly via pt-cli (same thing) -./vendor/bin/pt-cli check patterns/ --theme=elayne - -# Check a specific file -./vendor/bin/pt-cli check patterns/woocommerce/my-pattern.php --theme=elayne - -# With autofix -./vendor/bin/pt-cli check patterns/ --theme=elayne --autofix -``` - -**Pass 3 — sentinel runtime validator** (run from the theme directory; launches a real browser, logs into WP admin, inserts pattern into a draft page, saves, reads back JS block validation errors and content mismatches): - -```bash -# From theme directory -cd ~/code/imagewize.com/demo/web/app/themes/elayne - -# Single file -npm run validate:file -- patterns/my-pattern.php - -# All patterns -npm run validate - -# WooCommerce patterns -npm run validate:woo - -# Or directly via npx -npx sentinel patterns/my-pattern.php -npx sentinel patterns/ -npx sentinel --url=http://demo.imagewize.test/store patterns/woocommerce/ -``` - -**Pass 4 — HTML template compliance checker** (host machine; checks `templates/` and `parts/` .html files): - -Run after modifying any `.html` template or part file. Catches WooCommerce filter blocks missing `
` wrappers (WooCommerce 9.x+ save() change), `product-filters` div missing CSS custom properties, `taxQuery:{}` (object) that must be `[]` (array), missing `"theme"` attribute on `wp:template-part`, and unbalanced HTML tags. - -```bash -# Check templates and parts directories -pt-cli check:templates demo/web/app/themes/elayne/templates/ --theme=elayne -pt-cli check:templates demo/web/app/themes/elayne/parts/ --theme=elayne - -# With autofix (repairs taxQuery:{} → taxQuery:[] and adds missing "theme" to wp:template-part) -pt-cli check:templates demo/web/app/themes/elayne/templates/ --theme=elayne --autofix - -# Check a single template file -pt-cli check:templates demo/web/app/themes/elayne/templates/archive-product.html --theme=elayne -``` - -> Pass 1 requires the Trellis VM because WordPress needs a live database connection — the VM runs the database. Files sync automatically via Lima so patterns edited on the host are immediately available in the VM. **Important**: `limactl shell` does NOT support `--workdir` flag — use `trellis vm shell` or place `--workdir` BEFORE the VM name with `limactl shell`. macOS paths do not exist in the VM — always use VM-side paths like `/srv/www/demo.imagewize.com/current`. The `--compliance` flag on `wp pattern validate` warns that the compliance checker is not accessible inside the VM; always run Pass 2 separately on the host. - -The GitHub Actions workflow runs Pass 2 automatically on every PR. Passes 1, 3, and 4 require the local environment and run locally only. - -## Visual & Functional Testing - -### Playwright Browser Testing Script -The repository includes a Playwright-based browser testing script at `.playwright/scripts/test.js` for visual regression and CSS verification. This is **vital for testing** pattern rendering on the demo site. - -**Usage:** -```bash -# From repository root -node .playwright/scripts/test.js [action] [selector] [options] - -# Examples: -node .playwright/scripts/test.js http://demo.imagewize.test/kafe/ screenshot -node .playwright/scripts/test.js http://demo.imagewize.test/kafe/ css .fandb-hero-stamp --desktop -node .playwright/scripts/test.js http://demo.imagewize.test/ html -``` - -**Actions:** -- `screenshot [name]` — Take a full-page screenshot (optionally with custom name) -- `html` — Get page HTML for inspection -- `css ` — Check computed styles for a specific selector -- `eval ` — Run predefined evaluation functions -- `check ` — Check specific block configurations - -**Viewport Options:** -- `--mobile` (390×844) -- `--tablet` (768×1024) -- `--desktop` (1920×1080, default) -- `--viewport=WxH` (custom dimensions) - -**Tip:** Always run the rebuild script first, then Sentinel (Pass 3) after pattern changes, then use Playwright to verify the visual output matches designs. Sentinel validates block structure; Playwright validates visual rendering. - -## Key Components - -### Block Extensions - -1. **Navigation Block** (`assets/js/block-extensions/navigation.js`) - - "Clickable Parents" option + "Improved Chevrons" option - - Handler: `inc/block-extensions.php` filters `render_block` for `core/navigation` - -2. **Post Excerpt Block** (`assets/js/block-extensions/post-excerpt.js`) - - "Link to Post" option + "Underline Link" toggle - - Handler: `inc/block-extensions.php` filters `render_block` for `core/post-excerpt` - -**Architecture**: Vanilla JavaScript only (no build step, no JSX), uses `wp.hooks`/`wp.components`/`wp.blockEditor` APIs. - -### Custom Image Sizes (functions.php) -- `elayne-portrait-small` (380×570) — `elayne-portrait-medium` (380×507) — `elayne-portrait-large` (380×475) — `elayne-single-hero` (700×400) - -## WP-CLI & Server Access - -All WP-CLI commands must be run from the **Trellis VM**, not your local machine. - -```bash -# Single command from host -cd ~/code/imagewize.com/trellis -trellis vm shell --workdir /srv/www/demo.imagewize.com/current -- wp cache flush --path=web/wp - -# Multisite cache flush -trellis vm shell --workdir /srv/www/demo.imagewize.com/current -- \ - bash -c "wp site list --field=url --path=web/wp | xargs -n1 -I % wp --url=% cache flush --path=web/wp" -``` - -## Version Management - -**Version locations to update**: -1. `style.css` — `Version: X.X.X` -2. `readme.txt` — `Stable tag: X.X.X` -3. `CHANGELOG.md` — Add new version section - -## Debugging - -**Debug log:** -```bash -cd ~/code/imagewize.com/trellis -trellis vm shell -- tail -50 /srv/www/demo.imagewize.com/logs/debug.log -``` - -## WordPress Integration - -### Template Hierarchy - -| Template File | Pattern | Purpose | -|---|---|---| -| `404.html` | `elayne/template-page-404` | 404 error page | -| `archive.html` | `elayne/template-page-archive` | Category/tag/date archives | -| `front-page.html` | `elayne/template-index-grid` | Static homepage (overrides page content) | -| `home.html` | `elayne/template-index-grid` | Blog index | -| `index.html` | `elayne/template-index-grid` | Fallback template | -| `page.html` | `elayne/template-page` | Default page (with title) | -| `page-no-title.html` | `elayne/template-page-no-title` | Page without title section | -| `page-with-sidebar.html` | `elayne/template-page-right-sidebar` | Page with right sidebar | -| `search.html` | `elayne/template-page-search` | Search results | -| `single.html` | `elayne/template-post-centered` | Single post | - -Each HTML template references exactly one pattern using ``. - -### Template Parts -- `parts/header.html` — Site header with navigation -- `parts/footer.html` — Site footer - -### ⚠️ Front Page Template Behavior - -`templates/front-page.html` **overrides page content** when a static page is set as homepage. - -**Options:** -1. Edit `front-page.html` to include `` (lets editors customize homepage) -2. Delete `front-page.html` (WordPress falls back to page's assigned template) -3. Edit patterns directly (current approach — consistent homepage across installs) - -> See `docs/elayne/PAGE-TEMPLATES.md` for full template analysis and rationale. - -### Core Features Disabled -- Core block patterns removed (line 22 in functions.php) — only Elayne patterns available - -### Editor Styles -- `style.css` enqueued for both frontend and editor for WYSIWYG consistency From 64690ca6433b539dab502ed5afe4e73218564329 Mon Sep 17 00:00:00 2001 From: Jasper Frumau Date: Mon, 22 Jun 2026 09:15:45 +0700 Subject: [PATCH 2/3] Update AGENTS.md Documentation --- AGENTS.md | 418 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 269 insertions(+), 149 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e9bfe89..542e6b8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,28 +1,33 @@ # Repository Guidelines +Elayne is a premium WordPress block theme (FSE/block theme, WP 6.6+, PHP 8.0+, no build tools — direct PHP, HTML, and vanilla JavaScript). `theme.json` is the single source of truth for styles, colors, typography, and spacing. + +## Efficiency +- Avoid reading entire files when only a specific section is needed. +- Use `Grep` to locate relevant code before reading; prefer targeted reads with `offset`/`limit` over full file reads. + ## Project Structure & Module Organization -- Root is a WordPress block theme; primary code lives alongside `style.css` and `theme.json` for metadata and global styles. +- Root is a WordPress block theme; primary code lives alongside `style.css` (metadata only) and `theme.json` (global styles). - Block patterns live in `patterns/` (PHP files registering block markup); keep slugs/descriptions aligned to filenames. - Template parts sit in `parts/` (header/footer) and full templates in `templates/` and `index.php`. -- Shared assets live under `assets/` (`fonts/`, `styles/` for pattern-specific CSS) and translations in `languages/`. -- Reusable PHP helpers reside in `functions.php` and `inc/`; avoid putting logic in template files. -- **`.distignore` file**: Present in theme directory but ignored by git (see `demo/.gitignore`). Required for WordPress.org distribution to exclude dev files from ZIP package. Synced from standalone Elayne repo (`~/code/elayne/.distignore`). +- Shared assets live under `assets/` (`fonts/` — Mona Sans, Open Sans, Bitter; `styles/` for pattern-specific CSS) and translations in `languages/` (text domain `elayne`). +- Reusable PHP helpers reside in `functions.php` and `inc/` (e.g. `inc/block-extensions.php`); avoid putting logic in template files. +- **`.distignore` file**: Present in theme directory but ignored by git (see `demo/.gitignore`). Required for WordPress.org distribution to exclude dev files from the ZIP package. Synced from standalone Elayne repo (`~/code/elayne/.distignore`). ## Build, Test, and Development Commands - No JS build pipeline is required; theme assets are committed. Activate by placing the folder in `wp-content/themes/elayne/` and enabling it in WP Admin. -- **IMPORTANT**: All WP-CLI commands must be run from Trellis VM, NOT from local machine +- **IMPORTANT**: All WP-CLI commands must be run from Trellis VM, NOT from the local machine. - For CLI activation inside a Bedrock/Trellis install: `wp theme activate elayne --path=web/wp`. - Regenerate translations when strings change: `wp i18n make-pot . languages/elayne.pot`. - Flush caches after template or pattern edits if using object caching: `wp cache flush`. -- **Commit hygiene**: Demo theme commits must be attribution-free (no Claude/AI footers). +- **Commit hygiene**: Demo theme commits must be attribution-free (no Claude/AI/Mistral/Vibe footers). ### Local Development with Trellis VM -- Uses **Trellis VM** (Lima-based, NOT Vagrant) -- **Protocol**: Uses **HTTP** (not HTTPS) - Access via `http://demo.imagewize.test/` (NOT `https://`) -- **Access VM**: `cd ~/code/imagewize.com/trellis && trellis vm shell` -- **File Sync**: Automatic, real-time sync between host (`~/code/imagewize.com/demo/`) and VM (`/srv/www/demo.imagewize.com/`) -- **No manual file copying needed** - edits on host immediately available in VM -- **Common issue**: Changes not appearing = WordPress cache, NOT file sync. Solution: `wp cache flush --path=web/wp` +- Uses **Trellis VM** (Lima-based, NOT Vagrant). +- **Protocol**: Uses **HTTP** (not HTTPS) — access via `http://demo.imagewize.test/` (NOT `https://`). +- **Access VM**: `cd ~/code/imagewize.com/trellis && trellis vm shell`. +- **File Sync**: Automatic, real-time sync between host (`~/code/imagewize.com/demo/`) and VM (`/srv/www/demo.imagewize.com/`) via Lima — no manual rsync needed. +- **Common issue**: Changes not appearing = WordPress cache, NOT file sync. Solution: `wp cache flush --path=web/wp`. ### WP-CLI Commands (Must Run from Trellis VM) ```bash @@ -39,179 +44,294 @@ trellis vm shell --workdir /srv/www/demo.imagewize.com/current -- wp cache flush wp site list --field=url --path=web/wp | xargs -n1 -I % wp --url=% cache flush --path=web/wp ``` -### WordPress Development Mode -Enable in `config/environments/development.php`: -```php -Config::define('WP_DEVELOPMENT_MODE', 'theme'); +### WordPress Development Mode & Caching +- `WP_DEVELOPMENT_MODE=theme` is set in `config/environments/development.php` — bypasses theme.json/style transients on every request. Disable in production for performance. +- **mu-plugin active:** `demo/web/app/mu-plugins/fse-dev-mode.php` hooks `pre_get_block_template` and returns the filesystem `WP_Block_Template` via `get_block_file_template()` when `WP_ENV=development`. This bypasses `wp_template`/`wp_template_part` DB overrides — template and template-part file edits appear on plain refresh with no WP-CLI required. Templates with no matching filesystem file (WooCommerce archives, plugin templates) fall through to the DB normally. +- **With both active:** template/part edits → plain refresh; theme.json edits → hard refresh (Cmd+Shift+R) in the Site Editor to update React state. `wp cache flush` is rarely needed for normal theme development. +- **Style variation cache:** If `theme.json`/`styles/*.json` changes don't appear, switch style variations in the Site Editor (`Styles → Browse styles`) — switch away and back to force a recompile. Nuclear option: delete the `wp_global_styles` post type and flush cache. + +### Rebuild Demo Subsites from Patterns +After modifying pattern PHP files you **must** rebuild demo pages before testing — the rebuild script renders each pattern in the live WP context and overwrites `post_content`, identical to a fresh block-editor insert. Run from the VM: +```bash +# Single subsite (dev). Subsites: main, legal, kafe, nail-salon, plumbing, store, spa +wp --path=web/wp --url=demo.imagewize.test/kafe/ eval-file scripts/rebuild-demo-subsite.php kafe + +# Dry run first +WP_REBUILD_DRY_RUN=1 wp --path=web/wp --url=demo.imagewize.test/kafe/ eval-file scripts/rebuild-demo-subsite.php kafe +``` +**Workflow:** modify pattern → rebuild → flush cache → validate (sentinel) → verify visually (Playwright). + +### Pattern URL Behavior (Environment Moves) +`get_template_directory_uri()` is evaluated when a pattern is inserted; the resulting URL is hardcoded into `post_content`. After moving content between environments, run `wp search-replace` to swap URLs before going live: +```bash +ssh web@demo.imagewize.com "cd /srv/www/demo.imagewize.com/current && \ + wp search-replace 'http://demo.imagewize.test' 'https://demo.imagewize.com' \ + --all-tables --precise --path=web/wp && wp cache flush --path=web/wp" ``` -**Benefits**: Bypasses theme.json/pattern caching for immediate changes + +## WooCommerce Store Subsite +WooCommerce runs on a **subsite mounted at `/store/`**. All shop URLs are prefixed: + +| Page | URL | +|---|---| +| Shop (product catalog) | `http://demo.imagewize.test/store/shop/` | +| Product category | `http://demo.imagewize.test/store/product-category/{slug}/` | +| Single product | `http://demo.imagewize.test/store/product/{slug}/` | +| WP Admin | `http://demo.imagewize.test/store/wp-admin/` | + +**Template hierarchy** (block theme, `templates/`): `archive-product.html` → shop + fallback; `taxonomy-product_cat.html` → category archives; `taxonomy-product_tag.html` → tag archives; `single-product.html` → single product. + +**Filter blocks** (WooCommerce 10.7+): +- `woocommerce/product-filter-taxonomy` with `{"taxonomy":"product_cat"}` for categories — `product-filter-category` does NOT exist. +- `woocommerce/product-filter-attribute` — omit `attributeId` for distributable templates (renders an unconfigured placeholder the client configures via Site Editor — Ollie pattern). Include `attributeId` only for demo-specific templates. Verify IDs via `wp wc product_attribute list --path=web/wp --user=1`. +- `woocommerce/product-filter-price` — price range slider. + +**Demo store attribute IDs** (May 2026 — do NOT hardcode in distributable templates): `1` = Leather Colour (`pa_leather-colour`), `2` = Style (`pa_style`), `3` = Features (`pa_features`). + +## Design System +All design tokens live in `theme.json` — never hardcode colors, sizes, or spacing in patterns. + +**Color palette**: Brand — `primary` (teal), `primary-accent`, `primary-dark`; Contrast — `main` (dark gray), `main-accent` (medium gray); Base — `base` (white), `secondary` (light gray), `tertiary` (very light gray); Borders — `border-light`, `border-dark`. + +**Typography**: Mona Sans (headings), Open Sans (body), Bitter (optional serif). Font-size values (critical — prevents oversized headings): + +| Slug | Max value | Use for | +|---|---|---| +| `x-small` | 0.95rem | Labels, badges, captions | +| `small` | 1.05rem | Small body, buttons | +| `base` | 1.165rem | Body text | +| `medium` | 1.65rem | Lead text, stat labels | +| `large` | 2.75rem | H1 on dark hero, stat numbers | +| `x-large` | 3.5rem | Display H1 only | +| `xx-large` | 4.39rem | Rarely used — very large display only | + +**Spacing scale** (all `clamp()` responsive): `2-x-small`, `x-small`, `small`, `medium`, `large`, `x-large`, `xx-large`, `xxx-large` — ⚠️ `xx-small` does NOT exist; use `2-x-small` or `x-small`. Values (critical — prevents oversized pills/badges): + +| Slug | Value | +|---|---| +| `2-x-small` | clamp(0.25rem → 0.5rem) ~4–8px | +| `x-small` | clamp(0.375rem → 0.75rem) ~6–12px | +| `small` | clamp(0.5rem → 1rem) ~8–16px | +| `medium` | clamp(1.5rem → 2rem) ~24–32px ← LARGE, not "medium" | +| `large` | clamp(2rem → 3rem) ~32–48px | +| `x-large` | clamp(3rem → 5rem) ~48–80px | + +**Pill/badge padding rule:** Always `x-small` (vertical) + `small` (horizontal). Never `medium` — that is ~28px per side and makes any pill grotesquely wide. + +**Pill/badge shrink-wrap rule (CRITICAL — prevents full-column-width pills):** WordPress `is-layout-flow` columns are internally `flex-direction: column` flex containers. Any child is a flex item and gets its `display` blockified — `inline-block`/`inline-flex` both compute to `block` regardless of inline styles or CSS. The default `align-items: normal` acts as `stretch`, making every child span the full column width. To shrink-wrap a pill/badge inside a `wp:column`, add `align-self: flex-start` and `width: fit-content` to its **CSS rule** (not inline). `is-style-status-pill` works in the editorial header only because that header is a `flex-direction: row` container (cross-axis vertical → width is content-driven); inside a `wp:column` it would need the same fix. ## Coding Style & Naming Conventions -- PHP: follow WordPress coding standards (4-space indent, snake_case functions); keep logic minimal and filter-based. Use text domain `elayne` in translatable strings. +- PHP: follow WordPress coding standards (tab indent, snake_case functions); keep logic minimal and filter-based. Use text domain `elayne` in translatable strings. - Patterns: name files with kebab-case slugs (e.g., `hero-two-tone.php`) and match the `title`/`categories` to existing taxonomy. - CSS: favor block-level styles under `assets/styles/`; keep selectors scoped to block classes to avoid global leakage. - Templates/parts: prefer semantic HTML and block markup; avoid inline styles when theme.json can express the setting. +### PHP Code Quality (functions.php) +Always run phpcs/phpcbf **from the theme directory** so `phpcs.xml` (WordPress standards) is picked up automatically. Wrong working directory silently applies a different standard and can introduce hundreds of new violations. +```bash +cd demo/web/app/themes/elayne && vendor/bin/phpcs functions.php # check +cd demo/web/app/themes/elayne && vendor/bin/phpcbf functions.php # auto-fix, then re-check +``` +Common WordPress-standard traps: use `array()` — **never** `[]` short syntax; indent with **tabs**, not spaces; multi-line calls put opening `(` last on the line, each arg on its own line, closing `)` on its own line; array values align with the longest key. + ### Pattern Development Guidelines -- **NEVER use hardcoded media IDs** in `wp:image` blocks (e.g., `"id":59`) -- **NEVER use external URLs** (Unsplash, CDNs, etc.) - all images must be local files -- Always use direct file paths: `/patterns/images/filename.webp` -- **GPL compatibility**: All pattern images must be GPL-compatible or public domain (CC0, Pexels License, etc.) - - **Document sources in `readme.txt`** (Copyright section) - WordPress.org requirement - - Follow attribution format from existing images (lines 269-349 in readme.txt) - - **Preferred sources**: WordPress Openverse (openverse.org - filter by "Use commercially" + "Modify or adapt"), Pexels (GPL-compatible license), or custom photography - - **NEVER use**: not GPL-compatible images -- **Image optimization**: Use WebP format, optimize file sizes (<200KB), appropriate dimensions -- Hardcoded IDs cause performance issues: database queries for non-existent media, blinking/flashing effects, console errors -- All pattern images stored in `patterns/images/` directory -- Use semantic color/spacing variables: `var:preset|color|primary` -- Follow format: `elayne/pattern-name` for slugs +- **NEVER use hardcoded media IDs** in `wp:image` blocks (e.g., `"id":59`). +- **NEVER use external URLs** (Unsplash, CDNs, etc.) — all images must be local files. +- Always use direct file paths: `/patterns/images/filename.webp`. +- **GPL compatibility**: All pattern images must be GPL-compatible or public domain (CC0). Document sources in `readme.txt` (Copyright section) — WordPress.org requirement. Preferred sources: WordPress Openverse (filter "Use commercially" + "Modify or adapt") or custom photography. ⚠️ Pexels License is NOT accepted by WP.org. +- **Image optimization**: WebP format, file sizes <200KB, appropriate dimensions; all stored in `patterns/images/`. +- Use semantic color/spacing variables (`var:preset|color|primary`); slugs follow `elayne/pattern-name`. #### Use Native WordPress Blocks (CRITICAL) -- **NEVER use `wp:html` blocks** for content that can be created with native WordPress blocks -- **ALWAYS prefer native blocks**: Use `wp:list`, `wp:separator`, `wp:group`, `wp:columns`, etc. -- **Custom styling**: Add CSS classes and styles to `style.css` rather than inline HTML -- **Why?** Native blocks are editable in the block editor, support theme.json styling, and work with block patterns -- **Example - WRONG**: `
...
` -- **Example - CORRECT**: `` with CSS in `style.css` -- **Separator blocks**: Use `wp:separator` with `is-style-dots` class for dotted lines -- **Custom list styles**: Register CSS class like `is-style-checkmark-list` and apply to `wp:list` blocks -- **Benefits**: Editor compatibility, theme.json integration, pattern reusability, accessibility +- **NEVER use `wp:html` blocks** for content that can be created with native blocks (`wp:list`, `wp:separator`, `wp:group`, `wp:columns`, etc.). +- Custom styling: add CSS classes/styles to block-style CSS (or `style.css`) rather than inline HTML. +- WRONG: `
...
`. CORRECT: `` with CSS. Use `wp:separator` with `is-style-dots` for dotted lines. +- Benefits: editor compatibility, theme.json integration, pattern reusability, accessibility. #### Block Comment Attribute Structure (CRITICAL) -- **Block attributes must be correctly nested** in block comment JSON to avoid validation errors -- **Common mistake**: Nesting root-level attributes inside `style` object causes "Block validation failed" errors -- **Correct structure**: `backgroundColor`, `layout`, `align` are root-level attributes, NOT nested in `style` -- **Wrong**: `"style":{...,"backgroundColor":"base","layout":{...}}` -- **Correct**: `"style":{...},"backgroundColor":"base","layout":{...}` -- WordPress expects specific attribute placement based on block schema -- Validation errors appear in browser console: "Content generated by `save` function" vs "Content retrieved from post body" -- Always verify block comment JSON structure matches WordPress core block attribute schema -- **Whitespace between blocks**: NEVER add tabs, newlines, or spaces between an opening/closing `
` and the adjacent `` / `` comment — WordPress block serialization is whitespace-strict. Write markup compact/inline as the editor outputs it. -- **Button `fontSize`**: `wp:button` does NOT support root-level `fontSize` — use `"style":{"typography":{"fontSize":"var:preset|font-size|base"}}` instead. Root-level `"fontSize":"base"` on buttons causes block validation errors. -- **Image block — theme SVGs**: NEVER add `width`/`height` attributes to `` inside `wp:image` for theme-bundled SVGs — no media ID means WP can't validate dimensions and throws a block validation error. Use `` only. - -#### Pattern Metadata & Inline Styles (IMPORTANT) -- Keep the block comment and rendered wrapper in sync: include `metadata` (categories/patternName/name) when present, and mirror padding/margin values (including left/right) in the outer `div` inline styles so Gutenberg recovery does not rewrite the pattern. -- **Block comment balance**: Every `` must have a matching ``. Extra closing comments or missing wrappers can force Gutenberg to wrap the tail in a Classic block. +- Root-level attributes (`backgroundColor`, `layout`, `align`) must NOT be nested inside the `style` object. WRONG: `"style":{...,"backgroundColor":"base"}`. CORRECT: `"style":{...},"backgroundColor":"base"`. Mismatches cause "Block validation failed" (console: "Content generated by `save` function" vs "Content retrieved from post body"). +- **Whitespace between blocks**: NEVER add tabs, newlines, or spaces between an opening/closing `
` and the adjacent `` / `` comment — block serialization is whitespace-strict. Write markup compact/inline as the editor outputs it. +- **HTML comments**: NEVER add `` between `
` tags and block comments — causes validation failure. +- **Block comment balance**: every `` needs a matching ``; extra/missing wrappers force Gutenberg to wrap the tail in a Classic block. +- **Button `fontSize`**: `wp:button` does NOT support root-level `fontSize` — use `"style":{"typography":{"fontSize":"var:preset|font-size|base"}}`. Root-level `"fontSize":"base"` on buttons causes validation errors. +- **Button border-radius**: setting `border.radius` on `wp:button` without `border.color`/`border.width` makes the JS serializer inject `border-top-style:solid` → validation error. Always pair: `"border":{"radius":"var:preset|border-radius|sm","width":"0px"}`. +- **Image block — theme SVGs**: NEVER add `width`/`height` to `` inside `wp:image` for theme-bundled SVGs — no media ID means WP can't validate dimensions → validation error. Use `` only. When width/height ARE set (real media), `is-resized` class is required and `align` comes after width/height in JSON. +- **CSS vars in block JSON**: use `"color":"var:preset|color|border-light"`, NEVER `"var(--wp--preset--color--border-light)"` — the serializer Unicode-escapes `--`, causing a content mismatch. CSS vars inside HTML `style="..."` attributes are fine. +- **Ampersand / double-dash in block JSON**: never use `&` in attribute values (serializer escapes to `&` — use `and`/`+`); never use `--` in `className` BEM modifiers (escaped — use a single dash, and update CSS selectors). +- **metadata.name only on the root block**: `"metadata":{"name":...,"patternName":...}` belongs only on the OUTERMOST block of a pattern file. On inner/nested blocks it makes them appear as named patterns and confuses pattern tracking. + +#### Block HTML Validation — fontSize/fontFamily & blockGap (CRITICAL) +WordPress validates blocks by comparing the `save()` output against stored HTML; mismatches throw `Block validation failed`. + +**1. ROOT-level `fontSize`/`fontFamily` → CSS classes, NOT inline styles.** + +| Block JSON | Required HTML class | Wrong HTML (error) | +|---|---|---| +| `"fontSize":"x-large"` | `has-x-large-font-size` | `style="font-size:var(--wp--preset--font-size--x-large)"` | +| `"fontFamily":"var:preset\|font-family\|heading"` | `has-var-preset-font-family-heading-font-family` | `style="font-family:var(...)"` | + +(This differs from `"style":{"typography":{"fontSize":"var:preset|font-size|large"}}`, which intentionally produces an inline style.) + +**2. blockGap inline behavior (WP 6.6+).** WP stopped outputting inline `gap` for constrained/default layouts (handled by layout CSS). + +| Block | Layout | Gap requirement | +|---|---|---| +| `core/group` | `flex` | **Must have** `style="gap:..."` | +| `core/group` | `constrained`/`default` | **Must NOT have** inline `gap` | +| `core/columns` | any | **Must NEVER have** inline `gap` | + +More broadly: never emit `gap:`, spacing `margin-top/bottom`, or spacing `padding` as inline `style` on a `
` when a parent `blockGap` or flex/grid layout already controls it — WP applies gap via runtime `wp-container-*` classes, so inline `gap:` is dead markup sentinel strips. Set spacing on the PARENT via `blockGap`. #### Responsive Grid Layouts (CRITICAL) -- **Use grid layout with `minimumColumnWidth`** for responsive multi-column patterns (3→2→1 columns) -- **NEVER use `wp:columns` for pricing/feature grids** - goes 3→3(cramped)→1, bad tablet experience -- **NEVER use fixed `columnCount`** - forces exact column count at all screen sizes -- **Correct**: `{"layout":{"type":"grid","minimumColumnWidth":"20rem"}}` -- **Behavior**: Desktop (3 cols) → Tablet (2 cols) → Mobile (1 col) based on available space -- **Use for**: Pricing tables, feature grids, team grids, card layouts -- **Reference**: See `pricing-comparison.php` -- **Grid standards**: Use category tags plus consistent widths: `elayne/card-simple` = `18rem`, `elayne/card-extended` = `19rem`, `elayne/card-profiles` = `20rem`, text-heavy grids = `28-29rem`. -- **Centering rule**: Keep the outer full-width group as `layout: default`, then wrap the grid in an inner `alignwide` group so it centers inside the constrained container. - -#### Pattern Background Spacing (CRITICAL) -- **Always add margin reset** to patterns with background colors: `"margin":{"top":"0","bottom":"0"}` -- WordPress core adds automatic `margin-block-start` between blocks in constrained layouts -- Without margin reset, unwanted gaps appear between adjacent patterns with different backgrounds -- Use inline styles (Ollie approach) instead of global CSS overrides -- Example: `style="margin-top:0;margin-bottom:0;padding-top:var(--wp--preset--spacing--xxx-large);..."` -- Required for: Full-width sections, hero sections, CTAs, testimonials, feature grids with backgrounds - -#### Full-Width Pattern Layout (CRITICAL) -- **NEVER use constrained layout on outer `alignfull` group** - causes horizontal gaps/overflow -- **Root cause**: `"layout":{"type":"constrained","contentSize":"1200px"}` on `alignfull` group creates max-width that conflicts with full-width alignment -- **Correct approach**: - - Outer `alignfull` group: ALWAYS use `"layout":{"type":"default"}` - - Inner content groups: Use `"layout":{"type":"constrained","contentSize":"XXXpx"}` to center and limit width -- **Reference**: See `hero-two-tone.php` for working example -- **Wrong**: `` -- **Correct**: `` with nested constrained groups inside - -#### Pattern URLs & Environment Moves (IMPORTANT) -- `get_template_directory_uri()` is evaluated when a pattern is inserted; the resulting URL is hardcoded into `post_content`. -- After moving content between environments, run `wp search-replace` to swap `.test` URLs to production (and vice versa) before going live. - -#### Page Template Layout for Full-Width Patterns (CRITICAL) -- **Problem**: Page templates using `"layout":{"type":"default"}` on `post-content` prevent full-width patterns from breaking out -- **Root cause**: `default` layout constrains all children, while `constrained` layout allows `alignfull` to break out -- **Solution**: Page templates must use `{"layout":{"type":"constrained"}}` on `post-content` block -- **Fixed templates**: `template-page-wide.php`, `template-page-wide-no-title.php` updated to use constrained layout -- **Correct template**: `template-page-full.php` already correct (used by `page-no-title.html`) -- **Reference**: Based on Ollie theme's approach +- **ALWAYS use grid with `minimumColumnWidth`** for 3+ column patterns (true 3→2→1 responsive). **NEVER use `wp:columns`** for 3-column grids (goes 3→3-cramped→1, skips tablet) or fixed `columnCount`. +- Correct: `{"layout":{"type":"grid","minimumColumnWidth":"20rem"}}`. Widths: `elayne/card-simple` `18rem`, `elayne/card-extended` `19rem`, `elayne/card-profiles` `20rem`, text-heavy `28-29rem`. +- **Centering**: keep the outer full-width group as `layout: default`, then wrap the grid in an inner `alignwide` group. See `pricing-comparison.php`. Full details: `docs/elayne/GRID-LAYOUT-STANDARDS.md`. + +#### Full-Width Pattern Layout & Spacing (CRITICAL) +- **NEVER use constrained layout on an outer `alignfull` group** — causes horizontal gaps/overflow. Outer `alignfull` group ALWAYS `"layout":{"type":"default"}`; inner content groups use `"constrained"` with `contentSize`. See `hero-two-tone.php`. +- **Margin reset** on any background pattern: `"margin":{"top":"0","bottom":"0"}` (no units) — WP core adds `margin-block-start` between constrained-layout blocks, causing gaps between adjacent differently-colored sections. Use inline styles (Ollie approach), not global CSS overrides. +- **Page template** `post-content` block must use `"layout":{"type":"constrained"}` (NOT `default`) — otherwise `alignfull` patterns can't break out. + +#### Spacing & BlockGap +- **NO spacer blocks** — use `blockGap` on parent containers. **NO manual margins** on headings/paragraphs — let parent `blockGap` control spacing. +- **Horizontal padding** always on the outer container — `left/right: var:preset|spacing|medium`. +- Scale: `small` (tight grouping) → `medium` → `large` → `x-large` (major section breaks). Full details: `docs/elayne/DESIGN-REFACTOR.md`. + +#### Border Radius Presets (WP 6.9+) +Use `var:preset|border-radius|{slug}` — never hardcode px, and never the non-existent `var:preset|border|radius`. Slugs (from `theme.json → settings.border.radiusSizes`): `sm` 0.625rem (buttons), `md` 0.75rem (inner card elements), `lg` 1rem (card containers), `pill` 999px (badges/tags). Border width has no preset — always hardcode `1px`. Full details: `docs/elayne/BORDER-PRESETS.md`. + +#### Translation Readiness (CRITICAL — WP.org) +Every user-facing string MUST be wrapped — unwrapped strings cause WP.org rejection. + +| Content type | Function | +|---|---| +| Plain text in HTML tags | `` | +| Text with inline HTML (``, `
`, `
`) | `` | +| HTML attributes (alt, title, aria-label) | `` | + +**Wrap**: headings, paragraphs, list items, button labels, stat numbers, badge/CTA text, names, job titles, non-empty `alt`. **Don't wrap**: empty `alt=""`, block comment JSON, `get_template_directory_uri()` expressions, real emails (use `example@example.com`). Quick check: `grep -n ">\s*[A-Z][^<]*\s*<" patterns/your-pattern.php`. +> ⚠️ **Unicode in PHP**: single-quoted strings do NOT process `\u` escapes — `'–'` outputs literal `–`. Use the actual UTF-8 character (`'Mon–Fri · Sat'`) or a double-quoted string (`"\u{2013}"`). Never copy `\uXXXX` from JS into PHP single quotes. + +#### Custom Block Types +NEVER use `register_block_type()` in a theme — WP.org plugin-territory violation. Use the `render_block` filter on `core/group` blocks with a specific `className` (same pattern as the ticker). ### WooCommerce Patterns -- Use WooCommerce plugin patterns **as-is** (Tier 1) - these are **EXEMPT from Elayne's semantic variable rules** -- Style with theme CSS (Tier 2) when plugin output doesn't match Elayne designs -- Create custom patterns in `patterns/woocommerce/` (Tier 3) only if Tiers 1-2 fail -- **Naming:** Use `woo-` prefix (e.g., `woo-cart.php`, `woo-checkout.php`) -- **Categories:** Use only registered `elayne/woocommerce` - **NOT** `elayne/cart` or `elayne/checkout` -- **Colors:** Use registered theme.json palette (`primary`, `main`, `base`, `tertiary`, `primary-accent`) - **NEVER use charcoal or cream** -- **Single product:** Use product blocks directly - **NEVER wrap in `woocommerce/product-template`** -- **Archive pagination:** `product-collection` handles its own - **NEVER use standalone `query-pagination`** -- **Button attributes:** `className` before `style` (root-level attributes first) -- **Full-width:** Outer `alignfull` group must use `"layout":{"type":"default"}` - -## Pattern Compliance Checker +- **Three-tier strategy**: Tier 1 = use WooCommerce plugin patterns (`demo/web/app/plugins/woocommerce/patterns/*.php`) **as-is** — EXEMPT from Elayne's semantic-variable rules and compliance checks; Tier 2 = style with theme CSS/`theme.json`; Tier 3 = custom patterns in `patterns/woocommerce/` only if Tiers 1-2 fail. +- **Naming:** `woo-` prefix (e.g., `woo-cart.php`). **Categories:** only registered `elayne/woocommerce` — NOT `elayne/cart`/`elayne/checkout`. **Inserter:** set `Inserter: false` for page-level patterns (cart/checkout). +- **Colors:** registered theme.json palette only (`primary`, `main`, `base`, `tertiary`, `primary-accent`) — NEVER `charcoal`/`cream`. +- **Single product:** use product blocks directly — NEVER wrap in `woocommerce/product-template`; in templates use `post-title` with `__woocommerceNamespace`, not `woocommerce/product-title`. +- **Native WC blocks:** NEVER add `__woocommerceNamespace` to `product-image`, `product-price`, `product-rating`, `product-button`, `product-sale-badge`. +- **Archive/`product-collection`:** handles its own pagination — NEVER use standalone `query-pagination`; ALWAYS include full `"query":{...}` metadata and the `
` wrapper; use only `displayLayout` (never both `layout` and `displayLayout`). +- **Buttons:** `className` before `style` (root-level attributes first). **Full-width:** outer `alignfull` group must use `"layout":{"type":"default"}`. + +> Full pattern details with code examples: `docs/elayne/PATTERN-GUIDELINES.md`. +## Search/Replace Best Practices +Search/replace requires byte-for-byte matching — a single comma, brace, or space difference fails. +- **Use unique, context-aware patterns**: include surrounding code, block slugs, function/class names, or full `theme.json` property paths. Avoid generic terms (`"color"`, `"padding"`). +- **Pre-flight (mandatory)**: `grep -Fn 'exact text' patterns/file.php` first — if grep can't find it, the search text is wrong. For long block-comment lines, grep a short unique substring, then read the line to verify brace counts. Reveal hidden chars with `cat -A`. Commit before large replacements for easy rollback. +- **Most common failure — brace count**: `"margin":{"top":"0"}}` vs `}}}` — deeply nested JSON has many closing braces; one missing/extra `}` gives a ~99% fuzzy match but exact-match failure. Count: `}` closes the value object, the parent (`spacing`), the grandparent (`style`), then `,` before the next root attribute. + +## Pattern Validation (four-pass) +Run all four. Pass 1 fixes structural issues regex cannot catch; Pass 3 (sentinel) catches JS `save()` mismatches Pass 1 cannot see. + +> **Pass 1 vs Pass 3:** `wp pattern validate` (Pass 1) uses PHP `parse_blocks()` + `serialize_blocks()` — it does NOT run Gutenberg's JS `save()`. Issues only the JS serializer produces (`border-top-style:solid` injection, `has-text-color` before `has-{preset}-font-size` ordering, button link class ordering, `backgroundColor:"base"` being dropped) pass Pass 1 but fail in the browser. Pass 3 catches all of these. + +**Pass 1 — Gutenberg structural validator** (requires Trellis VM — database lives there): ```bash -# From monorepo root — check all theme patterns -php scripts/elayne/pattern-check/class-patterncompliancechecker.php \ - demo/web/app/themes/elayne/patterns/*.php +cd ~/code/imagewize.com/trellis && trellis vm shell \ + --workdir /srv/www/demo.imagewize.com/current -- \ + wp pattern validate web/app/themes/elayne/patterns/my-pattern.php # dry run +# add --fix to repair; pass a directory + --fix --log to write audit logs to docs/pattern-logs/YYYY-MM-DD/ +``` -# Check a specific file -php scripts/elayne/pattern-check/class-patterncompliancechecker.php \ - demo/web/app/themes/elayne/patterns/my-pattern.php +**Pass 2 — pt-cli compliance checker** (host, from theme dir; no WordPress needed). CI runs this on every PR via `.github/workflows/pattern-compliance.yml`: +```bash +cd ~/code/imagewize.com/demo/web/app/themes/elayne +composer check # all patterns (or: pt-cli check patterns/ --theme=elayne) +pt-cli check patterns/my-pattern.php --theme=elayne +pt-cli check patterns/ --theme=elayne --autofix ``` +The legacy PHP checker still works from the monorepo root: `php scripts/elayne/pattern-check/class-patterncompliancechecker.php demo/web/app/themes/elayne/patterns/*.php`. -CI runs automatically on every PR via `.github/workflows/pattern-compliance.yml`. +**Pass 3 — sentinel runtime validator** (theme dir; launches a real browser, logs into WP admin, inserts the pattern into a draft, saves, reads back JS validation errors and content mismatches): +```bash +cd ~/code/imagewize.com/demo/web/app/themes/elayne +npm run validate:file -- patterns/my-pattern.php # single +npm run validate # all +npm run validate:woo # WooCommerce +# or: npx sentinel patterns/ / npx sentinel --url=http://demo.imagewize.test/store patterns/woocommerce/ +``` + +**Pass 4 — HTML template compliance** (host; checks `templates/` and `parts/` .html files). Catches WooCommerce filter blocks missing `
` wrappers, `product-filters` missing CSS custom props, `taxQuery:{}` (must be `[]`), missing `"theme"` on `wp:template-part`, unbalanced tags: +```bash +pt-cli check:templates demo/web/app/themes/elayne/templates/ --theme=elayne +pt-cli check:templates demo/web/app/themes/elayne/parts/ --theme=elayne --autofix +``` + +## Visual Testing (Playwright) +Repo Playwright script at `.playwright/scripts/test.js` (run from repo root) — use the repo script, NOT MCP/browser tools. +```bash +node .playwright/scripts/test.js [action] [selector] [options] +# screenshot [name] | html | css | eval | check +# Viewports: --mobile (390×844) | --tablet (768×1024) | --desktop (1920×1080, default) | --viewport=WxH +``` +Tip: rebuild → sentinel (Pass 3) → Playwright. Sentinel validates block structure; Playwright validates visual rendering. ## Testing Guidelines -- Manual verification is primary: activate the theme, add each pattern to a page, and confirm layout/spacing matches design. -- Validate block templates in the editor to ensure no block validation errors appear. +- Manual verification is primary: activate the theme, add each pattern to a page, confirm layout/spacing matches design, and check the editor shows no block validation errors. - Run `wp i18n make-pot` if translations are touched to confirm the POT file updates cleanly. +## Key Components +- **Block extensions** (vanilla JS, no build step — uses `wp.hooks`/`wp.components`/`wp.blockEditor`): `assets/js/block-extensions/navigation.js` ("Clickable Parents" + "Improved Chevrons") and `post-excerpt.js` ("Link to Post" + "Underline Link"), with PHP `render_block` handlers in `inc/block-extensions.php`. +- **Custom image sizes** (`functions.php`): `elayne-portrait-small` (380×570), `elayne-portrait-medium` (380×507), `elayne-portrait-large` (380×475), `elayne-single-hero` (700×400). +- **Core block patterns removed** in `functions.php` — only Elayne patterns are available. `style.css` is enqueued for both frontend and editor (WYSIWYG consistency). + +## WordPress Template Hierarchy +Each HTML template references exactly one pattern via ``. + +| Template | Pattern | Purpose | +|---|---|---| +| `404.html` | `elayne/template-page-404` | 404 error page | +| `archive.html` | `elayne/template-page-archive` | Archives | +| `home.html` | `elayne/template-index-grid` | Blog index / static homepage | +| `index.html` | `elayne/template-index-grid` | Fallback | +| `page.html` | `elayne/template-page` | Default page | +| `page-no-title.html` | `elayne/template-page-no-title` | Page without title | +| `page-with-sidebar.html` | `elayne/template-page-right-sidebar` | Right sidebar | +| `search.html` | `elayne/template-page-search` | Search results | +| `single.html` | `elayne/template-post-centered` | Single post | + +⚠️ `front-page.html` has been removed (it caused override issues on multisite subsites); the homepage is assigned via the WordPress page editor. Template parts: `parts/header.html`, `parts/footer.html`. See `docs/elayne/PAGE-TEMPLATES.md`. + ## Versioning Checklist -- When bumping versions (e.g., to `1.0.0-beta.2`), update `style.css` header, `readme.txt` Stable tag and changelog section, and `CHANGELOG.md` release entry together. -- Match `readme.txt` changelog formatting to Moiraine: `== Changelog ==` header, entries like `= 1.0.0-beta.3 - 12/10/25 =` with bullet prefixes `NEW/ADDED/CHANGED/TECHNICAL` and concise sentences ending in periods. -- Keep `CHANGELOG.md` aligned to Keep a Changelog; include descriptive subsection titles (e.g., `### Added - ...`, `### Changed - ...`) similar to Moiraine’s style. -- Use `git status` / `git diff` to review current changes; compare against `main` when needed (`git diff main...HEAD`) before updating release notes. +Update together on every release: `style.css` header `Version:`, `readme.txt` `Stable tag:` + changelog section, and `CHANGELOG.md` release entry. +- Match `readme.txt` changelog to Moiraine: `== Changelog ==`, entries like `= 1.0.0-beta.3 - 12/10/25 =` with `NEW/ADDED/CHANGED/TECHNICAL` prefixes, concise sentences ending in periods. +- Keep `CHANGELOG.md` aligned to Keep a Changelog (`### Added - ...`, `### Changed - ...`). +- When updating `CHANGELOG.md`/`readme.txt`, new entries are ADDITIONS — do NOT describe them as "Changed" unless the file already existed on `main`. +- Review with `git status`/`git diff`; compare against `main` (`git diff main...HEAD`) before writing release notes. ## Commit & Pull Request Guidelines -- Use short, Title-Case commit messages focused on a single change (e.g., `Hero Pattern Update`). -- PRs should state purpose, affected paths (patterns, templates, assets), and manual test notes (browser/viewport and steps). -- Include screenshots or screen recordings for visual changes to patterns, templates, or global styles. -- Avoid committing secrets or environment config; only theme assets/code belong here. +- Short, Title-Case messages focused on a single change (e.g., `Hero Pattern Update`). +- **Atomic commits**: `git add` files individually or in small logical groups, each with a specific message — never stage multiple unrelated files together. +- **ALL commits**: attribution-free — no Claude/AI/Mistral/Vibe footers. +- PRs state purpose, affected paths (patterns/templates/assets), and manual test notes (browser/viewport + steps); include screenshots/recordings for visual changes. +- Do not commit secrets or environment config; only theme assets/code belong here. ## Server Access & Deployment - -### Accessing Live Demo Server -- **SSH as web user** (recommended for WP-CLI): `ssh web@demo.imagewize.com` -- **SSH as root** (server management): `ssh root@demo.imagewize.com` -- **Demo site paths on server (Bedrock structure):** - - Current release: `/srv/www/demo.imagewize.com/current/` - - Theme: `/srv/www/demo.imagewize.com/current/web/app/themes/elayne/` - - Uploads: `/srv/www/demo.imagewize.com/shared/uploads/` - - Logs: `/srv/www/demo.imagewize.com/logs/` - -### Common Server Operations +- **SSH as web user** (recommended for WP-CLI): `ssh web@demo.imagewize.com`; root for server management. +- **Server paths (Bedrock):** current release `/srv/www/demo.imagewize.com/current/`; theme `.../current/web/app/themes/elayne/`; uploads `/srv/www/demo.imagewize.com/shared/uploads/`; logs `/srv/www/demo.imagewize.com/logs/`. +- Debug log: `trellis vm shell -- tail -50 /srv/www/demo.imagewize.com/logs/debug.log`. ```bash -# SSH to demo server ssh web@demo.imagewize.com cd /srv/www/demo.imagewize.com/current - -# Check WordPress status (multisite) -wp site list --path=web/wp - -# Flush cache (multisite - all sites) +wp site list --path=web/wp # multisite status wp site list --field=url --path=web/wp | xargs -n1 -I % wp --url=% cache flush --path=web/wp - -# View error logs tail -f /srv/www/demo.imagewize.com/logs/error.log ``` - -### Deployment -- Managed via Trellis from repository root -- See main `CLAUDE.md` in repository root for deployment commands -- Demo site uses multisite configuration +- Deployment managed via Trellis from the repository root (see main `CLAUDE.md`); demo uses multisite. ## Security & Configuration Tips -- Do not commit `.env`, uploads, or build artifacts; only theme code and assets should live in the repo. +- Do not commit `.env`, uploads, build artifacts, or `.vibe/` directories; only theme code and assets belong here. - When working in Trellis/Bedrock, always pass `--path=web/wp` to WP-CLI to target the correct install. -- Keep licensed assets (fonts/images) documented in `assets/`; ensure redistribution rights before adding new media. +- Keep licensed assets (fonts/images) documented; ensure redistribution rights (GPL-compatible/CC0) before adding new media. From 5c8759a0e553f81b00dece13c3e621c92d7b1d65 Mon Sep 17 00:00:00 2001 From: Jasper Frumau Date: Mon, 22 Jun 2026 09:15:47 +0700 Subject: [PATCH 3/3] Bump Version to 4.6.3 --- CHANGELOG.md | 18 ++++++++++++++++++ readme.txt | 7 ++++++- style.css | 2 +- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e27356..e9c20b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [4.6.3] - 2026-06-22 + +### Changed + +**Mistral Vibe Configuration:** +- Migrated Vibe development instructions from `.vibe/prompts/vibe.md` to `AGENTS.md` for standardized AI agent guidance +- Updated `.vibe/config.toml` to use default CLI system prompt instead of custom vibe prompt +- Removed `.vibe/prompts/vibe.md` (content consolidated into AGENTS.md) + +**AGENTS.md Enhancements:** +- Added theme overview and efficiency guidelines +- Expanded project structure with font family, text domain, and file references +- Added WordPress Development Mode and mu-plugin caching documentation +- Added demo rebuild workflow and pattern URL environment migration instructions +- Added WooCommerce store subsite documentation with template hierarchy and filter blocks +- Updated commit hygiene rules to include Mistral/Vibe attribution exclusion +- Improved formatting consistency throughout + ## [4.6.2] - 2026-06-20 ### Fixed diff --git a/readme.txt b/readme.txt index ce30c92..55aa90c 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: block-patterns, block-styles, blog, custom-colors, custom-logo, custom-men Requires at least: 6.6 Tested up to: 7.0 Requires PHP: 8.0 -Stable tag: 4.6.2 +Stable tag: 4.6.3 License: GNU General Public License v3.0 (or later) License URI: https://www.gnu.org/licenses/gpl-3.0.html @@ -174,6 +174,11 @@ Elayne includes custom image sizes optimized for different layouts: == Changelog == += 4.6.3 - 06/22/26 = +* CHANGED: Migrated Mistral Vibe development instructions from .vibe/prompts/vibe.md to AGENTS.md for standardized AI agent guidance. +* CHANGED: Updated .vibe/config.toml to use default CLI system prompt instead of custom vibe prompt. +* CHANGED: Enhanced AGENTS.md with theme overview, WooCommerce subsite docs, demo rebuild workflow, mu-plugin caching, and pattern URL migration instructions. + = 4.6.2 - 06/20/26 = * FIXED: Added function_exists() guards around all WooCommerce functions to prevent fatal errors on non-WooCommerce sites. * FIXED: Category filter drawer safely skips enqueue when WooCommerce is not active. diff --git a/style.css b/style.css index 2b98bb5..87addb2 100644 --- a/style.css +++ b/style.css @@ -7,7 +7,7 @@ Description: Elayne is a premium full-site-editing block theme for professional Requires at least: 6.6 Tested up to: 7.0 Requires PHP: 8.0 -Version: 4.6.2 +Version: 4.6.3 License: GNU General Public License v3 or later License URI: https://www.gnu.org/licenses/gpl-3.0.html Text Domain: elayne