make.wordpress.org ![rw-book-cover](https://github.com/user-attachments/assets/936e6388-6dfa-4228-9225-744469a127f7) ## Metadata - Author: [[make.wordpress.org]] - Full Title: make.wordpress.org - Category: #articles - Document Tags: [[article]] [[processed]] - Summary: make.wordpress.org - URL: https://make.wordpress.org/core/2025/11/11/dataviews-dataform-et-al-in-wordpress-6-9/ This is a summary of the changes introduced in the “dataviews space” during the WordPress 6.9 cycle. They have been posted in [the corresponding iteration issue](https://github.com/WordPress/gutenberg/issues/70936) as well. There’s a new [issue for the WordPress 7.0 cycle](https://github.com/WordPress/gutenberg/issues/73076), subscribe there for updates. * [Field API](https://make.wordpress.org/core/2025/11/11/dataviews-dataform-et-al-in-wordpress-6-9/#field-api) * [DataViewsPicker](https://make.wordpress.org/core/2025/11/11/dataviews-dataform-et-al-in-wordpress-6-9/#dataviewspicker): selection focused component * [DataForm](https://make.wordpress.org/core/2025/11/11/dataviews-dataform-et-al-in-wordpress-6-9/#dataform) #### Field API For more information, consult the two reference documents: * the [developer docs](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#fields-api) for API description * the [storybook](https://wordpress.github.io/gutenberg/?path=/docs/dataviews-fieldtypes--docs) where users can interact with each field type in its different forms [Developer docs](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#type) The field `type` has been expanded to describe the default field’s behaviors for sorting, validation, filtering, editing, and rendering. The field author can still override those defaults, but they don’t need to, they can have a working field by just providing the type. ``` { id: 'fieldId', type: 'number' } ``` We’ve also expanded the initial 3 types into 13: | Field Type | 6.8 | 6.9 | | --- | --- | --- | | datetime | ✓ | ✓ | | integer | ✓ | ✓ | | text | ✓ | ✓ | | array | | ✓ | | boolean | | ✓ | | color | | ✓ | | date | | ✓ | | email | | ✓ | | media | | ✓ | | number | | ✓ | | password | | ✓ | | telephone | | ✓ | | url | | ✓ | Legend: * ✓ = Fully implemented with field type definition * Empty = Not available [Developer docs](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#isvalid) Validation has been completely overhauled to leverage a rule-base system. All field types support the `required` and `elements` rule, as well as defining custom validation via the `custom` function — that supports both sync and async modes. We plan to expand the available rules in future versions, follow-up [this issue](https://github.com/WordPress/gutenberg/issues/71500) for updates. ``` // 6.8 { isValid: ( item: Item, context?: ValidationContext ) => boolean; } // 6.9 { isValid: { required: boolean, element: boolean, custom: | ( ( item: Item, field: NormalizedField< Item > ) => null | string ) ) | ( ( item: Item, field: NormalizedField< Item > ) => Promise< null | string > ); } } ``` [Developer docs](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#getvalue-and-setvalue) The introduction of `setValue`, alongside the existing `getValue`, has added a few capabilities to the framework. See the related story: [live](https://wordpress.github.io/gutenberg/?path=/story/dataviews-dataform--data-adapter), [code](https://github.com/WordPress/gutenberg/blob/a56188fd8ddb72ecdb9881fcffc219094dfd573e/packages/dataviews/src/stories/dataform.story.tsx#L1950). ###### Working with nested data By using the dot notation in the `field.id` (e.g., `user.profile.name`), the `getValue` and `setValue` methods will automatically read and write the data from the corresponding object property — though field authors can still override `getValue` and `setValue` methods. ``` const data = { user: { profile: { name: 'John Doe', email: '[email protected]' } } }; const fields = [ { id: 'user.profile.name', // Dot notation for nested access label: 'User Name', type: 'text', }, { id: 'user.profile.email', label: 'Email', type: 'email', } ]; ``` `setValue` can be leveraged to decide which parts of the data should be updated, including modifying multiples parts of it. ``` const data = { product: { price: 10, quantity: 3, total: 30 // Derived from price × quantity } }; const fields = [ { id: 'product.price', label: 'Price', type: 'integer', // Updates total when price changes setValue: ( { item, value } ) => ({ product: { price: value, total: value * item.product.quantity } }) }, { id: 'product.quantity', label: 'Quantity', type: 'integer', // Updates total when quantity changes setValue: ( { item, value } ) => ({ product: { quantity: value, total: item.product.price * value } }) }, { id: 'product.total', label: 'Total', type: 'integer', readOnly: true // Calculated field, not editable } ]; ``` In certain situations, the data and the UI control representing the data need to be adapted. Field authors can use `getValue` and `setValue` for this. ``` const data = { user: { preferences: { notifications: true // Boolean in data } } }; const fields = [ { id: 'notifications', label: 'Notifications', type: 'boolean', Edit: 'radio', elements: [ { label: 'Enabled', value: 'enabled' }, { label: 'Disabled', value: 'disabled' } ], // Transform boolean to string for UI getValue: ( { item } ) => item.user.preferences.notifications === true ? 'enabled' : 'disabled', // Transform string back to boolean for data setValue: ( { value } ) => ({ user: { preferences: { notifications: value === 'enabled' } } }) } ]; ``` [Developer docs](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#edit) Field authors can define how a field behaves when it’s edited. They can provide a custom edit control, but also select one of bundled ones — which have been expanded from 5 to 16: | Control | Description | 6.8 | 6.9 | | --- | --- | --- | --- | | `datetime` | Date time picker | ✓ | ✓ | | `integer` | Number input | ✓ | ✓ | | `radio` | Radio buttons | ✓ | ✓ | | `select` | Dropdown select | ✓ | ✓ | | `text` | Text input | ✓ | ✓ | | `array` | Multi-select | | ✓ | | `checkbox` | Checkbox control | | ✓ | | `color` | Color picker | | ✓ | | `date` | Date picker | | ✓ | | `email` | Email input | | ✓ | | `password` | Password input | | ✓ | | `telephone` | Phone input | | ✓ | | `textarea` | Multi-line text | | ✓ | | `toggle` | Toggle switch | | ✓ | | `toggleGroup` | Button group | | ✓ | | `url` | URL input | | ✓ | Additionally, some bundled edit controls now support a configuration option to control its behavior or look-and-feel. ``` // Control the rows in a textarea { type: 'text', Edit: { control: 'textarea', rows: 5 } } // Add prefixes/suffixes to control { type: 'text', Edit: { control: 'text', prefix: DollarPrefix, // React component suffix: USDSuffix, // React component } } ``` ![Image](https://github.com/user-attachments/assets/6e311f39-0b8b-4a94-8c17-3f4696d61051) [Developer docs](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#filterby) Filters have gained more operators (from 6 to 22) and they are now bound to the field type. The initial 6 operators available (`is`, `isNot`, `isAny`, `isNone`, `isAll`, `isNotAll`) have been expanded into 22 total: * for integer and number: `lessThan`, `greaterThan`, `lessThanOrEqual`, `greaterThanOrEqual`, `between` * for date and datetime: `before`, `after`, `beforeInc`, `afterInc`, `on`, `notOn`, `inThePast`, `over`, `between` * for text: `contains`, `notContains`, `startsWith` The addition of new field types and edit controls has also expanded the filters available, that are now dependent on the field type, and they include support for user input as well: | User input | Date filter | | --- | --- | | ImageImage Image | Image | [Developer docs](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#getelements) We’ve introduced a `getElements` async function that fetches elements on demand, only when they are needed. This is a new API that will continue to evolve, follow-up changes at [70834](https://github.com/WordPress/gutenberg/issues/70834). This API can be seen in use in the Pages screen of the Site Editor. The author filter and edit control won’t fetch the authors until the user interacts with those controls. We’ve added a `readOnly` property (boolean) to mark fields that cannot be edited. In edit contexts, they’ll be displayed using the `render` property. For example, this can be useful when displaying non-editable metadata (file size, etc.). #### DataViews For more information, consult the two reference documents: [Developer docs](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#view-object) All the bundled layouts –table, grid, and list– support now grouping the items by a given field by declaring a `groupByField` in the view. Follow [issue](https://github.com/WordPress/gutenberg/issues/57967) for updates, and take a look at the [storybook](https://wordpress.github.io/gutenberg/?path=/story/dataviews-dataviews--group-by-layout). ``` { groupByField: 'fieldId' } ``` | grid | list | table | | --- | --- | --- | | Image | Image | Image | Locked filters are filters that cannot be edited or removed by the user. They appear in the filters UI but are marked as read-only, ensuring certain filtering conditions are always applied. ``` { filters: [ { field: 'status', operator: OPERATOR_IS_ANY, value: 'publish', isLocked: true, } ] } ``` ![Image](https://github.com/user-attachments/assets/161a40bc-ce9e-4079-a021-4a5ced848610) ###### Table layout: align and lock movers There are two new options that apply to the `table` layout: ``` { type: 'table', layout: { styles: { fieldId: { align: 'start' | 'center' | 'end' } }, enableMoving: false } } ``` * `align` is a new property to control the horizontal alignment of content within the cells. It’s specificied per field in the layout. * `enableMoving`: boolean to control whether the fields can be moved around. True by default. If false, it removes the moving controls in the table header and disables moving the fields via the view config as well. | Table | View config | | --- | --- | | Image | Image | [Developer docs](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#actions-api) The modal actions have now more options to control its behavior: * `modalHeader`: `string` | `( ( items: Item[] ) => string );`. Can now take a function to dynamically set the header based on the selected items. * `modalSize`: `small` | `medium` | `large` | `fill`. Controls the size of the modal. * `modalFocusOnMount`: `true` | `false` | `firstElement` | `firstContentElement`. Controls the focus behavior when the modal opens. [Developer docs](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#paginationinfo-object) All bundled layouts -table, list, and grid- now support infinite scroll. It’s enabled per view type, and DataViews takes a `infiniteScrollHandler` function that listens to scroll events and handles the data retrieval. See storybook [live](https://wordpress.github.io/gutenberg/?path=/story/dataviews-dataviews--infinite-scroll) and [implementation](https://github.com/WordPress/gutenberg/blob/906ce54fc84b996efc56b70626a9051a0e87f3d5/packages/dataviews/src/stories/dataviews.story.tsx#L428) for details. ``` const view = { layout: 'grid', infiniteScrollEnabled: boolean } const paginationInfo = { totalItems: totalItems, totalPages: totalPages, infiniteScrollHandler: () => { /* Fetch data, update view, etc. */ } }; return ( <DataViews view={view} paginationInfo={paginationInfo} ); ``` [Developer docs](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#renderitemlink-react-componenttype) The `renderItemLink` prop lets you provide a custom component that wraps clickable fields. It can render regular links, but also allows integration with routing libraries (like TanStack Router or React Router). The component receives the following props: * `item`: The data item that was clicked * Additional standard HTML anchor props (className, style, etc.) ``` <DataViews renderItemLink={ ( { item, ...props } ) => ( <Link to={ `/sites/${ item.slug }` } preload="intent" { ...props } /> ) } /> ``` [Developer docs](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#config-perpagesizes-number) Prop to configure the list of `perPageSizes` available in the view config. Defaults to `[10, 20, 50, 100]`). ![Image](https://github.com/user-attachments/assets/8e7198e2-b5da-45b9-8131-133d37c5111a) [Developer docs](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#empty-react-node) An element to display when the `data` prop is empty. Defaults to `<p>No results</p>`. We’ve exported many of the subcomponents DataViews is made up of, for them to be reused to build UIs. When DataViews receives no children, it renders its complete built-in UI (search bar, filter controls, view config, layout, etc.): ``` <DataViews data={ posts } fields={ fields } view={ view } onChangeView={ setView } actions={ actions } paginationInfo={ paginationInfo } /> ``` When children are provided, you can build custom layouts while leveraging DataViews’ internal state management and data handling logic: ``` <DataViews data={ posts } fields={ fields } view={ view } onChangeView={ setView } paginationInfo={ paginationInfo } > <DataViews.Search /> <DataViews.Layout /> <DataViews.Pagination /> </DataViews> ``` DataViews exposes 9 subcomponents for free composition: | Component | Purpose | | --- | --- | | DataViews.BulkActionToolbar | Toolbar for bulk actions | | DataViews.Filters | Filter controls panel | | DataViews.FiltersToggle | Button to show/hide filters panel | | DataViews.FiltersToggled | Badge showing active filters count | | DataViews.Footer | Component that renders pagination and bulk actions | | DataViews.Layout | Renders the actual data (grid/table/list) | | DataViews.LayoutSwitcher | Buttons to switch between layouts | | DataViews.Pagination | Page navigation controls | | DataViews.Search | Search input field | | DataViews.ViewConfig | Button to open view configuration | #### Persist views via `@wordpress/views` [Documentation](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-views/). A new package for managing DataViews view state with persistence using WordPress preferences. The `@wordpress/views` package provides: * **Persistence**: Automatically saves and restores DataViews state using `@wordpress/preferences` * **View Modification Detection**: Tracks when views differ from their default state * **Reset Functionality**: Simple reset to default view capability * **Clean Integration**: Drop-in replacement for manual view state management Usage: ``` // In route loader const view = await loadView( { kind: 'postType', name: 'wp_template', slug: 'active', defaultView, queryParams: { /* ... */ }, } ); // In screen const { view, updateView, isModified, resetToDefault } = useView( { kind: 'postType', name: 'wp_template', slug: 'active', defaultView, queryParams: { /* ... */}, } ); ``` #### DataViewsPicker DataViewsPicker is a selection-focused variant of DataViews designed for building item picker interfaces. Use cases include a media picker for selecting images ([#71944](https://github.com/WordPress/gutenberg/pull/71944)), or a generalised post picker for selecting posts or page parents ([#71128](https://github.com/WordPress/gutenberg/issues/71128)). It currently only supports a grid layout view. * Selection Management: Track which items users have selected via selection state and onChangeSelection callbacks * Action Buttons: Include action buttons (like “Confirm” or “Cancel”) that operate on selected items via the actions prop * Familiar DataViews API: Same field definitions, filtering, pagination, and view configuration as DataViews * Customizable Layouts: Supports DataViews picker-specific layouts (to begin with, there is just a grid picker view available) * Default UI: Like DataViews, uses a pre-built interface including search, filters, layout switcher, and action toolbar—or use custom children to build your own Basic usage: ``` <DataViewsPicker data={items} fields={fields} selection={selectedIds} onChangeSelection={setSelectedIds} view={view} onChangeView={setView} paginationInfo={{ totalItems: 100, totalPages: 10 }} actions={[ { id: 'cancel', label: 'Cancel', callback: () => {...} }, { id: 'confirm', label: 'Confirm', isPrimary: true, callback: () => {...} }, ]} defaultLayouts={{ [LAYOUT_PICKER_GRID]: {} }} /> ``` #### DataForm For more information, consult the two reference documents: [Developer docs](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#form-field-api) The `form` API has been updated to accommodate the changes to existing layouts and the introduction of two new ones: `card` and `row`. There are two new properties, `openAs` and `summary`, to configure the behavior of the layout. `openAs` determines how the panel opens, either as a `dropdown` (default) or a `modal`. `summary` controls what fields summarize the panel, while before the first children was used. ![Image](https://github.com/user-attachments/assets/30653cb4-a8cb-4b9a-b02d-e5a491bb770a) The new `card` layout is a container layout: it wraps other layouts (`regular`, `panel`, etc.) within a card component. * `withHeader`: controls whether the card has a header * `isOpened`: controls how the card loads (opened or closed) * `summary`: a mechanism to render fields in the header, and control when they are displayed, either when the card is collapsed (the default) or always ![Image](https://github.com/user-attachments/assets/73cfd025-1128-46a9-8705-92878d4ca0a1) [Developer docs](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#row), [Storybook](https://wordpress.github.io/gutenberg/?path=/story/dataviews-dataform--layout-row). The new `row` layout is a container layout: it enables positioning other layouts horizontally. * `alignment`: control vertical alignment of fields within the row * `styles`: provides flex styles, for the width to be adjusted per field ![Image](https://github.com/user-attachments/assets/f9b0b4a0-f98e-4743-b62d-f0b78f52b545) Validation has been revamped in 6.9: it’s now controlled (DataForm has a `validity` prop), and supports asynchronous validation. All the DataForm controls gained support for all validation rules (required, elements, and custom). See related *Field API updates* and the [Field API validation](https://github.com/WordPress/gutenberg/issues/71500) issue. There’s a new `useFormValidity` hook to compute the `validity` prop, and the `isItemValid` utility has been removed., make.wordpress.org, make.wordpress.org, 01k9w4nng6zq498dx3pz2vmskj.