Element-query tables (Pro)
The thing a WordPress table plugin cannot do, because WordPress has no element query. Point a table at your content and it keeps itself current.
Defining one
On a table's edit screen, set Source to An element query, then:
| Field | What goes in it |
|---|---|
| Element type | Entries, categories, assets, users, Commerce products — anything registered as an element type |
| Criteria | Query parameters as JSON: {"section": "products", "orderBy": "title asc", "limit": 200} |
| Columns | One row per column: a heading, what it reads, and the value |
| Include a header row | Whether the column headings become row 1 |
A column reads one of three things:
- An attribute —
title,postDate,url - A custom field — the field's handle
- An object template —
{{ element.url }}, or any Twig you like. Bothelementand Craft's ownobjectare available.
Values are stringified sensibly on the way out: dates are formatted, elements become their labels, and a list of related elements becomes a comma-separated list.
Materialised, not live
The grid is built and stored, not resolved when the page renders. A table on a busy page must not run an element query per visitor, and a query table has to behave exactly like a hand-typed one — same caching, same export, same embed.
So freshness is kept by rebuilding:
- Saving an element of a matching type queues a rebuild on a 30-second debounce, so a resave of 400 entries costs one rebuild rather than four hundred.
- Refresh now on the table's edit screen rebuilds immediately.
php craft legs/tables/refreshrebuilds every query table — the cron option if you would rather not rebuild on save at all. TurnrefreshOnElementSaveoff in that case.
The matching is deliberately coarse: any element of the configured type schedules a rebuild, rather than Legs trying to work out whether this element would have matched that criteria. Getting that wrong in the strict direction means a table that quietly stops updating, which is far worse than an occasional unnecessary rebuild of a 500-row query.
Safety rails
Criteria are filtered against a list of parameters a table has any business setting — Craft::configure() would happily set any public property on the query, and a stored config is not a place to accept arbitrary ones. limit is always applied, defaulting to 500 and capped at 5,000: a query table with no limit is a table that can grow to 40,000 rows without anyone deciding it should.
On a multi-site install
A translated query table runs its query per site — the entries in a Spanish section are not the entries in an English one — and each site's grid is built and saved on its own. A shared one is built once and copied everywhere. See multi-site.