Filter the demo's projects archive - #169
Merged
Merged
Conversation
Nothing demonstrated query filters, the query_* helpers and a cached filter URL together, so the feature existed and no page showed it working. The form uses only what WordPress already parses: project_category is the taxonomy's own query var, and WP_Query reads it from a checkbox group's array or from a comma string alike. No hook, no config, no custom parameter. Fetch enhances it without taking the no-JS path away, and deliberately fetches the whole filtered page rather than a section URL — a page is cached and a section is Cache-Control: no-store, so the whole page comes back without PHP. Also fix the guide's terms() calls: Timber provides get_terms(). Co-authored-by: Claude <claude@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #169 +/- ##
============================================
+ Coverage 85.66% 85.67% +0.01%
- Complexity 2535 2537 +2
============================================
Files 194 194
Lines 6988 6997 +9
============================================
+ Hits 5986 5995 +9
Misses 1002 1002
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Checking the demo's filter form against a real WordPress found two faults in helpers nothing had exercised. query_contains() read a comma-separated value as one opaque string, so a page reached by a shared filter link showed every checkbox unchecked — and the Link Toggle Filter example in the guide could never mark a term active. query_url_toggle() built its URLs by handing an array to add_query_arg(), which spells them `genre[0]=rock`. That is a name the page cache cannot key, so every toggle link was a permanent bypass; joining with a comma and keeping the separator literal puts them back on the fast path, since `%2C` is no better. Co-authored-by: Claude <claude@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the gap #166 identified after #167 landed: query filters, the
query_*helpers and a cached filter URL all existed, and no page in the repository showed them working together.The demo's projects archive now filters by series and sort order.
It uses no framework feature to filter
project_categoryis the taxonomy's own query var, andorderbyis a public one. There is noquery-filters.config.php, noQueryFiltersHook, and no custom parameter.That is not a shortcut —
WP_Query::parse_tax_query()reads the var from a checkbox group's array or from a comma string, sorts the terms and builds oneINclause from either:So
?project_category[]=corridors&project_category[]=osakaand?project_category=corridors,osakaare the same query, and both are cached by #167 — the first through the drop-in, the second through nginx.The smoke suite asserts that equivalence against a real
WP_Queryrather than trusting it, along with an unknown slug returning nothing rather than everything.It works without JavaScript
A plain
method="get"form with a submit button.FetchandActionfrom@studiometa/uienhance it —data-on:change="Fetch.fetch()"— and@studiometa/ui/autoloadis already imported, so no JavaScript was added to the theme.The enhanced request is still cached
Fetchgets nodata-option-src, unlike the pagination links beside it. It fetches the whole filtered page and swaps the two elements whoseidit finds — the index and the count.A section response would be smaller and would never be cached:
Cache-Control: private, no-storeis by design. A filtered page is served from the cache without starting PHP, so the whole page off a warm file beats a fragment off a cold render. This is theFrame-versus-sections decision #166 said had to be made before templates were written; the comment in the template records why.page-cache.config.phpkeys the two arguments the form emits, withorderbygiven as a value list rather than a regex:cacheQueryArgs: [ 'project_category' => '^[a-z0-9-]+(?:,[a-z0-9-]+)*$', 'orderby' => ['date', 'title'], ],Also in here
docs/guide/query-filters.mdusedterms('genre')in four examples. That function does not exist — Timber providesget_terms(). Fixed, and the guide now says plainly that a registered public taxonomy is filterable with no configuration at all, which is what the demo shows;QueryFiltersConfigis for operators, private vars and non-public taxonomies.Two bugs found by running it against ddev
Checking the form against the real demo install caught two faults in helpers nothing had exercised. Both are fixed here, with unit tests.
query_contains()could not read the comma spelling.?project_category=still-life,portraitfiltered correctly and showed every checkbox unchecked, because the value was compared as one opaque string. The guide's own "Link Toggle Filter" example had the same bug: it could never mark a term active. Verified in ddev — 0 boxes checked before, 2 after.query_url_toggle()produced URLs the cache can never key. It handed an array toadd_query_arg(), which spells itproject_category[0]=still-life. An indexed name is not a keyed argument, so every toggle link was a permanent bypass. It now joins with a comma — and keeps the separator literal, becauseadd_query_arg()percent-encodes it to%2Cand%is not a character the cache will put in a filename, so the encoded form bypasses just as surely.Checked against local ddev
/projects/?project_category[]=still-life?project_category[]=still-life&project_category[]=portrait?project_category=still-life,portrait?project_category=nopeThe smoke assertions were run in the container: 25 passed before this branch, 29 after, so all four new filtering assertions ran and passed. The one pre-existing failure (
run.sh imported the uploads fixture) appears in both runs and is an artifact of invokingwp eval-filedirectly rather than throughrun.sh.The checkout used for that testing was restored to a clean tree afterwards, vendor included.
Verification
composer test:demo88 passed,composer lintandcomposer analyseclean of anything new, docs build with no dead links.php -lon all changed PHP; stylelint back to its pre-existing baseline with nothing added.🤖 Generated with Claude Code
https://claude.ai/code/session_01KZusb9DU8coizq3CDgHEqi