wp-dataviews-dataform
Build or audit data-driven WordPress plugin interfaces with the public `@wordpress/dataviews` DataViews, DataViewsPicker, and DataForm components. Use for sortable/filterable/paginated admin datasets, item pickers, quick edit forms, field and action contracts, server-driven REST
Install
npx skills add https://github.com/Lonsdale201/wp-agent-skills/tree/main/wordpress/wp-dataviews-dataform
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install lonsdale201-wp-agent-skills@llmmart
git clone https://github.com/Lonsdale201/wp-agent-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole lonsdale201/wp-agent-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
WordPress DataViews and DataForm
Use the public package to build consistent dataset and editing interfaces. It renders UI; it does not fetch, authorize, mutate, paginate, or persist records for you.
Choose the component
DataViews: browse, search, filter, sort, paginate, select, and act on items.DataViewsPicker: controlled single- or multi-item selection. It supports onlypickerGridandpickerTable, and has a narrower action contract.DataForm: edit one record or a deliberately composed bulk-edit value.
Do not use these components to replace a simple settings field or a tiny static list. Their value starts when fields, views, selection, or actions are reusable.
WordPress build contract
Install @wordpress/dataviews and, when building with @wordpress/scripts,
import from its WordPress entry point:
import { DataForm, DataViews } from '@wordpress/dataviews/wp';
Do not copy examples that import the package root unchanged into a WordPress
build. The official package explicitly requires /wp for that environment.
Ship the package CSS through the plugin build and declare wp-components as a
dependency of the plugin stylesheet. Never depend on private exports obtained
through @wordpress/private-apis or code copied from the Site Editor bundle.
Keep the data flow controlled
const [ view, setView ] = useState( {
type: 'table',
page: 1,
perPage: 20,
search: '',
filters: [],
sort: { field: 'title', direction: 'asc' },
fields: [ 'status', 'updated' ],
} );
<DataViews
data={ records }
fields={ fields }
view={ view }
onChangeView={ setView }
getItemId={ ( item ) => String( item.id ) }
paginationInfo={ { totalItems, totalPages } }
isLoading={ isLoading }
/>
The consumer owns every transition. Convert view.page, perPage, search,
filters, and sort into an allowlisted server query, fetch the matching page,
then return correct totals. Do not fetch every record and claim server
pagination. Reset or clamp an invalid page when filters reduce the result set.
Every item needs a stable unique ID. The default reads item.id; otherwise pass
getItemId. Never use an array index because sorting and pagination make
selection nondeterministic.
Define fields once
A field is the shared read, sort, filter, render, edit, and validation contract.
Prefer declared type, label, elements, filterBy, and visibility flags.
Use getValue/setValue when the stored shape is nested, and custom render
or Edit only when the built-ins cannot express the behavior.
Rendering a label is not authorization. Treat all returned data as potentially
sensitive, and escape or render it as React text rather than injecting HTML.
For complete field/action shapes and picker restrictions, read
references/contracts-and-security.md.
Actions and writes
- Use
isEligibleanddisabledfor UX, not security. - Re-check capability and object ownership in the REST mutation callback.
- Use a nonce/cookie or application-password authentication appropriate to the client; DataViews adds none.
- Make bulk actions explicit with
supportsBulk; handle partial failures and report per-item results rather than pretending the batch was atomic. - Refresh or update local records only after the server confirms the write.
DataViewsPicker supports callback actions, not RenderModal; it does not
support isEligible. All actions must agree on supportsBulk for multi-select.
Its selection and onChangeSelection props are required.
DataForm is an edit buffer
const [ edits, setEdits ] = useState( {} );
const edited = { ...record, ...edits };
<DataForm
data={ edited }
fields={ fields }
form={ { layout: { type: 'panel' }, fields: [ 'title', 'status' ] } }
onChange={ ( nextEdits ) => setEdits( ( old ) => ( { ...old, ...nextEdits } ) ) }
validity={ validity }
/>
onChange receives edits; it does not save them. Run client validation for
feedback and authoritative server validation on submit. Preserve unsaved edits
across query refreshes deliberately, and clear them only after success or an
explicit cancel.
WordPress 7.1 compatibility
- WordPress component form controls now use a 40px default. Remove
__next40pxDefaultSize; passingfalseno longer restores 36px. - The deprecated
Navigationcomponent is removed; useNavigator. __experimentalApplyValueToSidesis removed.- Several Emotion-backed components moved toward SCSS modules. Do not depend on
generated class names;
View's legacycssprop is a no-op. - Non-paginated core-data entities now return all records. Do not keep a
per_page: -1workaround as a correctness requirement, and review loops that assumed the former accidental ten-item slice.
Test matrix
Test empty/loading/error states, one and many pages, filter + sort combinations, page shrinkage, duplicate-looking labels with distinct IDs, keyboard-only selection, screen-reader labels, unavailable actions, bulk partial failure, server validation, authorization failure, network races, RTL, narrow viewports, and reduced motion. Abort or ignore stale responses so a slow old query cannot overwrite a newer view.
Cross-references
wp-view-config-apifor Site Editor view configuration and persistence.wp-rest-apifor the server/client boundary.wp-plugin-assets-loadingfor generated asset files and dependencies.
References
- DataViews package: https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/
- View persistence package: https://developer.wordpress.org/block-editor/reference-guides/packages/packages-views/
- WordPress 7.1 editor components: https://make.wordpress.org/core/2026/07/23/editor-components-updates-in-wordpress-7-1/
- WordPress 7.1 miscellaneous editor changes: https://make.wordpress.org/core/2026/08/04/miscellaneous-block-editor-changes-in-wordpress-7-1/
Files (wp-agent-skills)
-
agents
-
openai.yaml 246 B
interface: display_name: "WordPress DataViews and DataForm" short_description: "Build data-driven WordPress admin interfaces safely." default_prompt: "Use $wp-dataviews-dataform to design or audit a WordPress DataViews/DataForm interface."
-
-
references
-
contracts-and-security.md 2.6 KB
# DataViews/DataForm contracts and security ## DataViews ownership boundary The component owns rendering and interaction. The consumer owns: - fetching and normalizing `data`; - stable item IDs; - controlled `view` and `selection` state; - translating view changes into local or server-side operations; - pagination totals and race control; - action authorization and mutations; - persistence and error handling. `paginationInfo` contains `totalItems` and `totalPages`; it does not paginate the dataset. For local data, use a tested local filter/sort/paginate pipeline. For a REST-backed dataset, send only allowlisted query values and render the returned page. ## Field review Check every field for: - unique `id`, meaningful `label`, and accurate scalar `type`; - `getValue`/`setValue` symmetry for derived or nested data; - correct `elements` value types (do not mix numeric and string IDs); - server-supported sorting/filtering before enabling those controls; - safe React rendering without `dangerouslySetInnerHTML`; - visibility and read-only behavior that does not masquerade as authorization; - deterministic formatters for dates, numbers, and locales; - validation rules duplicated authoritatively on the server. ## Action review DataViews actions can include eligibility, disabled state, bulk support, callbacks, and modal rendering. Eligibility is evaluated in the browser and is not a capability check. The server must reject unauthorized IDs even if an attacker crafts the REST call directly. For bulk writes, define whether the contract is best-effort or atomic. If the server is best-effort, return item-level successes/errors and reconcile the visible page. Do not remove all selected rows after a partial failure. DataViewsPicker is narrower: - controlled `selection` and `onChangeSelection` are required; - only `pickerGrid` and `pickerTable` layouts are supported; - only callback actions are supported, not `RenderModal`; - `isEligible` is unsupported; - all actions need `supportsBulk: true` for multi-selection; - provide `itemListLabel` when no associated heading labels the listbox. ## Async race pattern Use an `AbortController`, query-library cancellation, or a monotonically increasing request token. When view A starts, view B starts, then A returns last, discard A. Track loading and error state per current query, not globally. ## Version discipline Treat the public package documentation and TypeScript definitions as the contract. Do not unlock `privateApis`, import from core's built Site Editor bundle, or select generated class names. Pin npm dependencies, rebuild asset metadata, and test against the oldest and newest supported WordPress versions.
-
-
SKILL.md 6.5 KB
--- name: wp-dataviews-dataform description: >- Build or audit data-driven WordPress plugin interfaces with the public `@wordpress/dataviews` DataViews, DataViewsPicker, and DataForm components. Use for sortable/filterable/paginated admin datasets, item pickers, quick edit forms, field and action contracts, server-driven REST queries, validation, selection, accessibility, and WordPress 7.1 component migrations. license: GPLv2-or-later metadata: wp-skills-author: "Soczó Kristóf" wp-skills-contact: "mailto:lonsdale201@hotmail.com" wp-skills-plugin: "wordpress" wp-skills-plugin-version-tested: "7.1" wp-skills-wp-version-tested: "7.1" wp-skills-php-min: "7.4" wp-skills-last-updated: "2026-08-20" --- # WordPress DataViews and DataForm Use the public package to build consistent dataset and editing interfaces. It renders UI; it does not fetch, authorize, mutate, paginate, or persist records for you. ## Choose the component - `DataViews`: browse, search, filter, sort, paginate, select, and act on items. - `DataViewsPicker`: controlled single- or multi-item selection. It supports only `pickerGrid` and `pickerTable`, and has a narrower action contract. - `DataForm`: edit one record or a deliberately composed bulk-edit value. Do not use these components to replace a simple settings field or a tiny static list. Their value starts when fields, views, selection, or actions are reusable. ## WordPress build contract Install `@wordpress/dataviews` and, when building with `@wordpress/scripts`, import from its WordPress entry point: ```js import { DataForm, DataViews } from '@wordpress/dataviews/wp'; ``` Do not copy examples that import the package root unchanged into a WordPress build. The official package explicitly requires `/wp` for that environment. Ship the package CSS through the plugin build and declare `wp-components` as a dependency of the plugin stylesheet. Never depend on private exports obtained through `@wordpress/private-apis` or code copied from the Site Editor bundle. ## Keep the data flow controlled ```jsx const [ view, setView ] = useState( { type: 'table', page: 1, perPage: 20, search: '', filters: [], sort: { field: 'title', direction: 'asc' }, fields: [ 'status', 'updated' ], } ); <DataViews data={ records } fields={ fields } view={ view } onChangeView={ setView } getItemId={ ( item ) => String( item.id ) } paginationInfo={ { totalItems, totalPages } } isLoading={ isLoading } /> ``` The consumer owns every transition. Convert `view.page`, `perPage`, `search`, `filters`, and `sort` into an allowlisted server query, fetch the matching page, then return correct totals. Do not fetch every record and claim server pagination. Reset or clamp an invalid page when filters reduce the result set. Every item needs a stable unique ID. The default reads `item.id`; otherwise pass `getItemId`. Never use an array index because sorting and pagination make selection nondeterministic. ## Define fields once A field is the shared read, sort, filter, render, edit, and validation contract. Prefer declared `type`, `label`, `elements`, `filterBy`, and visibility flags. Use `getValue`/`setValue` when the stored shape is nested, and custom `render` or `Edit` only when the built-ins cannot express the behavior. Rendering a label is not authorization. Treat all returned data as potentially sensitive, and escape or render it as React text rather than injecting HTML. For complete field/action shapes and picker restrictions, read `references/contracts-and-security.md`. ## Actions and writes - Use `isEligible` and `disabled` for UX, not security. - Re-check capability and object ownership in the REST mutation callback. - Use a nonce/cookie or application-password authentication appropriate to the client; DataViews adds none. - Make bulk actions explicit with `supportsBulk`; handle partial failures and report per-item results rather than pretending the batch was atomic. - Refresh or update local records only after the server confirms the write. `DataViewsPicker` supports callback actions, not `RenderModal`; it does not support `isEligible`. All actions must agree on `supportsBulk` for multi-select. Its `selection` and `onChangeSelection` props are required. ## DataForm is an edit buffer ```jsx const [ edits, setEdits ] = useState( {} ); const edited = { ...record, ...edits }; <DataForm data={ edited } fields={ fields } form={ { layout: { type: 'panel' }, fields: [ 'title', 'status' ] } } onChange={ ( nextEdits ) => setEdits( ( old ) => ( { ...old, ...nextEdits } ) ) } validity={ validity } /> ``` `onChange` receives edits; it does not save them. Run client validation for feedback and authoritative server validation on submit. Preserve unsaved edits across query refreshes deliberately, and clear them only after success or an explicit cancel. ## WordPress 7.1 compatibility - WordPress component form controls now use a 40px default. Remove `__next40pxDefaultSize`; passing `false` no longer restores 36px. - The deprecated `Navigation` component is removed; use `Navigator`. - `__experimentalApplyValueToSides` is removed. - Several Emotion-backed components moved toward SCSS modules. Do not depend on generated class names; `View`'s legacy `css` prop is a no-op. - Non-paginated core-data entities now return all records. Do not keep a `per_page: -1` workaround as a correctness requirement, and review loops that assumed the former accidental ten-item slice. ## Test matrix Test empty/loading/error states, one and many pages, filter + sort combinations, page shrinkage, duplicate-looking labels with distinct IDs, keyboard-only selection, screen-reader labels, unavailable actions, bulk partial failure, server validation, authorization failure, network races, RTL, narrow viewports, and reduced motion. Abort or ignore stale responses so a slow old query cannot overwrite a newer view. ## Cross-references - `wp-view-config-api` for Site Editor view configuration and persistence. - `wp-rest-api` for the server/client boundary. - `wp-plugin-assets-loading` for generated asset files and dependencies. ## References - DataViews package: <https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/> - View persistence package: <https://developer.wordpress.org/block-editor/reference-guides/packages/packages-views/> - WordPress 7.1 editor components: <https://make.wordpress.org/core/2026/07/23/editor-components-updates-in-wordpress-7-1/> - WordPress 7.1 miscellaneous editor changes: <https://make.wordpress.org/core/2026/08/04/miscellaneous-block-editor-changes-in-wordpress-7-1/>
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.