Commit 668724a11cb for woocommerce
commit 668724a11cbf71f5003f1e5caa8ed29145a29b66
Author: Raluca Stan <ralucastn@gmail.com>
Date: Tue Jul 21 15:40:13 2026 -0400
docs: audit and tighten AI agent instruction files
Trim duplicated general guidance and fix stale references across the
CLAUDE.md/AGENTS.md instruction files, keeping only what is specific to
this repo.
- AGENTS.md: add a block.json field-types note pointing at the Gutenberg
Block Metadata reference, and flag that style/editorStyle/script/
viewScript are string | string[] so readers must handle both shapes.
- client/admin/CLAUDE.md: replace the generic WAI-ARIA how-to (semantic
HTML, ARIA patterns, examples, checklist, resources) with a pointer to
the WordPress Accessibility Handbook and WAI-ARIA Authoring Practices,
keeping only the WooCommerce-specific testing-query guidance.
- src/Internal/Admin/Settings/CLAUDE.md: correct the WooPaymentsRestController
path (now under PaymentsProviders/WooPayments/) and drop the stale
"Known Issues Fixed" table.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
diff --git a/AGENTS.md b/AGENTS.md
index 4e99d8a30b8..b90a849050e 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -199,6 +199,10 @@ Do not add `default` values to block attributes in `block.json`.
- Defaults can create subtle conflicts with `theme.json`, block supports, editor controls, deprecations, and migrations.
- During implementation or review, flag any newly inserted `default` in `block.json`.
+### `block.json` Field Types
+
+Consult the [Gutenberg Block Metadata reference](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/) as the source of truth for `block.json` field types. Several fields (`style`, `editorStyle`, `script`, `viewScript`) accept `string | string[]`, so code that reads them must handle both shapes — don't assume a string.
+
## Interactivity API Stores
Most WooCommerce Interactivity API stores are **private by design**. Exception: the `woocommerce/product-filters` store is public for Product Filters inner-block extensibility.
diff --git a/plugins/woocommerce/client/admin/CLAUDE.md b/plugins/woocommerce/client/admin/CLAUDE.md
index 5e5297b68f0..582558f306b 100644
--- a/plugins/woocommerce/client/admin/CLAUDE.md
+++ b/plugins/woocommerce/client/admin/CLAUDE.md
@@ -316,205 +316,15 @@ When rendering disabled/unsupported features, pass minimal props to prevent inad
## Accessibility (WAI-ARIA)
-### Critical Rules for Accessible Components
+All UI components must follow WAI-ARIA guidelines. This section captures only the
+WooCommerce-specific guidance; for the general rules (semantic HTML first, ARIA
+patterns for dialogs/forms/status, focus management, jest-axe) follow the
+[WordPress Accessibility Handbook](https://make.wordpress.org/accessibility/handbook/)
+and the [WAI-ARIA Authoring Practices](https://www.w3.org/WAI/ARIA/apg/).
-All UI components must follow WAI-ARIA (Web Accessibility Initiative - Accessible Rich Internet Applications) guidelines to ensure the admin interface is usable by everyone, including users with disabilities.
-
-### Semantic HTML First
-
-Always use semantic HTML before adding ARIA attributes:
-
-```typescript
-// GOOD - Semantic HTML
-<button onClick={handleClick}>Save</button>
-
-// BAD - Non-semantic with ARIA
-<div role="button" onClick={handleClick}>Save</div>
-
-// GOOD - Use <label> for form fields
-<label htmlFor="gateway-name">Gateway Name</label>
-<input id="gateway-name" type="text" />
-
-// BAD - Using aria-label only
-<input type="text" aria-label="Gateway Name" />
-```
-
-### Required ARIA Patterns
-
-**Interactive Elements:**
-
-- All buttons must have accessible names (visible text or `aria-label`)
-- Icon-only buttons MUST have `aria-label`
-- Disabled elements should have `aria-disabled="true"`
-
-```typescript
-// Icon button
-<button aria-label="Close dialog">
- <CloseIcon />
-</button>
-
-// Button with loading state
-<button disabled={isLoading} aria-disabled={isLoading}>
- {isLoading ? 'Loading...' : 'Submit'}
-</button>
-```
-
-**Status and State:**
-
-- Use `aria-live` for dynamic content updates
-- Status badges should use `role="status"` or `aria-label`
-- Loading states need `aria-busy="true"`
-
-```typescript
-// Status badge
-<span className="status-badge" role="status" aria-label="Payment gateway is active">
- Active
-</span>
-
-// Live region for notifications
-<div aria-live="polite" aria-atomic="true">
- {notificationMessage}
-</div>
-
-// Loading state
-<div aria-busy={isLoading} aria-label="Loading payment methods">
- {content}
-</div>
-```
-
-**Landmarks and Navigation:**
-
-- Use semantic landmarks: `<nav>`, `<main>`, `<aside>`, `<header>`, `<footer>`
-- Add `aria-label` to multiple landmarks of same type
-- Ensure proper heading hierarchy (`<h1>` → `<h2>` → `<h3>`)
-
-```typescript
-// Multiple navigation regions
-<nav aria-label="Main navigation">...</nav>
-<nav aria-label="Settings tabs">...</nav>
-
-// Main content area
-<main aria-label="Payment settings">...</main>
-```
-
-**Forms and Inputs:**
-
-- Associate labels with inputs using `htmlFor`/`id`
-- Use `aria-describedby` for help text and errors
-- Mark required fields with `aria-required="true"` or `required`
-
-```typescript
-// Form field with help text
-<label htmlFor="api-key">API Key</label>
-<input
- id="api-key"
- type="text"
- required
- aria-describedby="api-key-help"
- aria-invalid={hasError}
-/>
-<span id="api-key-help">Enter your payment gateway API key</span>
-{hasError && (
- <span id="api-key-error" role="alert">
- Invalid API key format
- </span>
-)}
-```
-
-**Dialogs and Modals:**
-
-- Use `role="dialog"` or `role="alertdialog"`
-- Add `aria-modal="true"` for modal dialogs
-- Include `aria-labelledby` pointing to title
-- Trap focus within modal
-
-```typescript
-<div
- role="dialog"
- aria-modal="true"
- aria-labelledby="dialog-title"
- aria-describedby="dialog-description"
->
- <h2 id="dialog-title">Confirm Setup</h2>
- <p id="dialog-description">Are you sure you want to enable this gateway?</p>
- <button onClick={handleConfirm}>Confirm</button>
- <button onClick={handleCancel}>Cancel</button>
-</div>
-```
-
-### Testing Accessibility
-
-**Use React Testing Library's accessibility queries (preferred order):**
-
-1. `getByRole` - Best for interactive elements
-2. `getByLabelText` - Best for form inputs
-3. `getByText` - For visible text content
-4. `getByTitle` - For elements with title attribute
-
-```typescript
-import { render, screen } from '@testing-library/react';
-
-describe('PaymentGatewayItem', () => {
- it('has accessible status badge', () => {
- render(<PaymentGatewayItem status="active" />);
-
- // Query by role
- const badge = screen.getByRole('status', { name: /active/i });
- expect(badge).toBeInTheDocument();
- });
-
- it('has accessible setup button', () => {
- render(<PaymentGatewayItem />);
-
- // Button with accessible name
- const button = screen.getByRole('button', { name: /complete setup/i });
- expect(button).toBeInTheDocument();
- });
-
- it('has properly labeled form inputs', () => {
- render(<GatewaySettings />);
-
- // Query by label
- const apiKeyInput = screen.getByLabelText(/api key/i);
- expect(apiKeyInput).toBeRequired();
- });
-});
-```
-
-**Test keyboard navigation:**
-
-```typescript
-import userEvent from '@testing-library/user-event';
-
-it('supports keyboard navigation', async () => {
- const user = userEvent.setup();
- render(<PaymentGatewayList />);
-
- // Tab through interactive elements
- await user.tab();
- expect(screen.getByRole('button', { name: /setup/i })).toHaveFocus();
-
- // Activate with keyboard
- await user.keyboard('{Enter}');
- expect(mockOnSetup).toHaveBeenCalled();
-});
-```
-
-**Automated accessibility testing:**
-
-Consider using `jest-axe` for automated checks:
-
-```typescript
-import { axe, toHaveNoViolations } from 'jest-axe';
-
-expect.extend(toHaveNoViolations);
-
-it('has no accessibility violations', async () => {
- const { container } = render(<PaymentGatewayItem />);
- const results = await axe(container);
- expect(results).toHaveNoViolations();
-});
-```
+**Test with React Testing Library's accessibility queries**, in priority order:
+`getByRole` (interactive elements) → `getByLabelText` (form inputs) → `getByText`
+→ `getByTitle`. Prefer these over `data-testid` so tests assert the accessible name.
### Common WooCommerce Admin Patterns
@@ -536,27 +346,6 @@ import { Button, Modal, Notice } from '@wordpress/components';
<Notice status="error">Failed to connect</Notice>
```
-### Checklist for New Components
-
-Before marking a component as complete:
-
-- [ ] Uses semantic HTML elements where possible
-- [ ] All interactive elements are keyboard accessible (Tab, Enter, Space)
-- [ ] All images/icons have alternative text or `aria-label`
-- [ ] Form inputs have associated labels
-- [ ] Error messages are announced (use `role="alert"` or `aria-live`)
-- [ ] Focus is managed properly (dialogs, dynamic content)
-- [ ] Color is not the only way to convey information
-- [ ] Component passes `jest-axe` checks (if configured)
-- [ ] Tested with screen reader queries (`getByRole`, `getByLabelText`)
-
-### Resources
-
-- **WAI-ARIA Authoring Practices**: <https://www.w3.org/WAI/ARIA/apg/>
-- **React Testing Library**: <https://testing-library.com/docs/queries/about/#priority>
-- **WordPress Accessibility Handbook**: <https://make.wordpress.org/accessibility/handbook/>
-- **axe DevTools**: Browser extension for accessibility testing
-
### Common Violations to Avoid
| Issue | Wrong | Correct |
diff --git a/plugins/woocommerce/src/Internal/Admin/Settings/CLAUDE.md b/plugins/woocommerce/src/Internal/Admin/Settings/CLAUDE.md
index 3f4f277802f..b817022ccd4 100644
--- a/plugins/woocommerce/src/Internal/Admin/Settings/CLAUDE.md
+++ b/plugins/woocommerce/src/Internal/Admin/Settings/CLAUDE.md
@@ -27,11 +27,12 @@
```text
Settings/
-|-- PaymentsRestController.php # Main REST endpoint
-|-- WooPaymentsRestController.php # WooPayments endpoints
-|-- Payments.php # Business logic
-|-- PaymentsProviders.php # Provider aggregation
-`-- Utils.php # Utilities
+|-- PaymentsRestController.php # Main REST endpoint
+|-- Payments.php # Business logic
+|-- PaymentsProviders.php # Provider aggregation
+|-- Utils.php # Utilities
+`-- PaymentsProviders/WooPayments/
+ `-- WooPaymentsRestController.php # WooPayments endpoints
```
## Critical Patterns
@@ -77,15 +78,6 @@ $schema = array(
);
```
-## Known Issues Fixed
-
-| File | Line | Issue | Fix |
-|------|------|-------|-----|
-| PaymentsRestController.php | 885-895 | `messages` uses `items` | Changed to `additionalProperties` |
-| WooPaymentsRestController.php | 1066-1076 | `messages` uses `items` | Changed to `additionalProperties` |
-| WooPaymentsRestController.php | 1107 | `type: enum` | Changed to `type: string` |
-| WooPaymentsRestController.php | 1246 | `type: enum` | Changed to `type: string` |
-
## Known Issues (Incomplete Schemas)
### onboarding.state Schema (PaymentsRestController.php:880-884)
@@ -189,7 +181,7 @@ array(
| File | Endpoint | Key Methods |
|------|----------|-------------|
| PaymentsRestController.php | `/wc-admin/settings/payments/*` | `get_providers()`, `set_country()`, `update_providers_order()` |
-| WooPaymentsRestController.php | `/wc-admin/settings/payments/providers/woopayments/*` | `get_onboarding_details()` |
+| PaymentsProviders/WooPayments/WooPaymentsRestController.php | `/wc-admin/settings/payments/providers/woopayments/*` | `get_onboarding_details()` |
| Payments.php | N/A (business logic) | `get_payment_providers()`, `get_payment_extension_suggestions()` |
## Linting