Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,11 @@ Fund search results are returned using the archive template via `ucscgiving_fund
- UCSC-2022 theme (template parts referenced in block templates)

## Testing
There is no automated test suite. Validate changes manually:
`composer test` runs a PHPUnit suite; `composer lint` runs PHPCS. Both run on every pull request via `.github/workflows/ci.yml` on PHP 8.1 and 8.4.

The suite stubs WordPress (`tests/bootstrap.php`) rather than running inside it, so it covers only functions that are pure once WordPress is stubbed. Everything else still needs manual validation:
- Test both Priority and Standard fund types for correct linking behavior
- Verify block bindings render correct URLs in the block editor and on the front end
- Check the "Fund Search" block variation appears in the block inserter
- Validate ACF fields save correctly and that values appear in templates
- Run `composer lint` before committing to ensure WordPress Coding Standards compliance
- Run `composer lint` and `composer test` before committing; CI runs both and will fail the PR otherwise
7 changes: 5 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@ npm install # Node dev deps (@wordpress/scripts, commit-and-tag-versio

composer lint # PHPCS across the repo
composer lint-fix # PHPCBF auto-fix
composer test # PHPUnit (needs ext-mbstring)

npm run zip # Build distributable ZIP (wp-scripts plugin-zip)
npm run dryrun # Preview version bump + changelog
npm run release # Tag a release and update CHANGELOG.md
```

There is **no automated test suite** — no PHPUnit, no wp-env config, no JS tests. `composer lint` is the only mechanical gate. Validate behavior by hand against a WordPress install with ACF Pro and the `ucsc-2022` theme active.
`composer lint` and `composer test` both run on every pull request via `.github/workflows/ci.yml` (PHP 8.1 and 8.4). `release.yml` still only fires on tags.

`composer lint` runs on every pull request via `.github/workflows/ci.yml` (PHP 8.1 and 8.4), so a style regression fails the PR. `release.yml` still only fires on tags.
**The PHPUnit suite stubs WordPress rather than running inside it.** `tests/bootstrap.php` supplies WordPress stand-ins, so the suite needs no WordPress, no database, no ACF Pro licence and no theme — but it therefore only covers functions that are pure once WordPress is stubbed. There is no wp-env config and no JS test suite, both deliberately; see ROADMAP §3.

Anything touching a running WordPress — block template registration, the ACF JSON round-trip, the fund-type save cycle — still has to be validated by hand against an install with ACF Pro and the `ucsc-2022` theme active.

## Repository shape

Expand Down
44 changes: 33 additions & 11 deletions ROADMAP.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Roadmap

Engineering roadmap for the UCSC Giving Functionality plugin, derived from the state of the repository as of **2026-07-31** (v0.5.8).
Engineering roadmap for the UCSC Giving Functionality plugin, derived from the state of the repository as of **2026-08-04** (v0.5.8).

This is a technical roadmap, not a product plan. Items are grounded in open issues, in-flight pull requests, and observed characteristics of the codebase — it does not attempt to set feature direction, which is the University Advancement web team's call. Sequencing below reflects dependency order and risk, not committed dates.

Expand All @@ -11,15 +11,17 @@ This is a technical roadmap, not a product plan. Items are grounded in open issu
| Item | Tracking | State |
|---|---|---|
| Dual source of truth for fund type | [#3](https://github.com/ucsc/ucsc-giving-functionality/issues/3) | Open, **needs a decision** — see [§1](#1-resolve-the-dual-source-of-truth-for-fund-type) |
| `CLAUDE.md` / `ROADMAP.md` project context | [#122](https://github.com/ucsc/ucsc-giving-functionality/issues/122) | Landed in [#125](https://github.com/ucsc/ucsc-giving-functionality/pull/125) |

### Needs a decision

**#3 needs an owner to pick a data model.** The issue has been rewritten around the root cause rather than the double-save symptom; §1 below is the decision it is waiting on. PR [#21](https://github.com/ucsc/ucsc-giving-functionality/pull/21) — a Copilot draft that added a third writer on `rest_after_insert_fund` to correct the other two — was **closed unmerged** on 2026-08-04. It had gone stale and conflicted with [#121](https://github.com/ucsc/ucsc-giving-functionality/pull/121), which rewrote `ucscgiving_link_filter()` in the same file, and it treated the symptom rather than the dual ownership.

### Recently landed

- [#121](https://github.com/ucsc/ucsc-giving-functionality/pull/121) — seven correctness and hygiene fixes: a `search_template` filter that had never applied, an unguarded `get_current_screen()` fatal, and a permalink filter that read loop state instead of its own `$post` argument. Also repaired `composer lint`, which failed outright with no path argument.
- [#131](https://github.com/ucsc/ucsc-giving-functionality/pull/131) ([#128](https://github.com/ucsc/ucsc-giving-functionality/issues/128)) — the PHPUnit harness described in §3. First automated behavioral coverage in the repo.
- [#130](https://github.com/ucsc/ucsc-giving-functionality/pull/130) ([#127](https://github.com/ucsc/ucsc-giving-functionality/issues/127)) — `ci.yml`, so pull requests are validated at all. Also declared the PHP floor (8.1), which had been recorded in neither `composer.json` nor the plugin header, and aligned the WPCS target version with `Requires at least`.
- [#125](https://github.com/ucsc/ucsc-giving-functionality/pull/125) ([#122](https://github.com/ucsc/ucsc-giving-functionality/issues/122)) — `CLAUDE.md` and this roadmap.
- [#121](https://github.com/ucsc/ucsc-giving-functionality/pull/121) — seven correctness and hygiene fixes: a `search_template` filter that had never applied, an unguarded `get_current_screen()` fatal, and a permalink filter that read loop state instead of its own `$post` argument. Also repaired `composer lint`, which failed outright with no path argument. Two of these now have regression tests, added in #131.
- [#124](https://github.com/ucsc/ucsc-giving-functionality/pull/124) — the plugin header version updater matched a single digit per segment, so it would have silently corrupted the `Version:` header at 0.5.10 and could not parse the `v*.*.*-rc.*` tags `release.yml` already triggers on.

---
Expand Down Expand Up @@ -57,22 +59,41 @@ Options range from cheap to thorough:

The middle option also gives the existing settings page a reason to exist beyond displaying the plugin description.

## 3. Establish a test harness
## 3. Test harness

There is currently **no automated test coverage of any kind** — no PHPUnit, no `.wp-env.json`, no JS tests. `composer lint` is the only mechanical gate, and it checks style, not behavior.
**Largely done.** [#127](https://github.com/ucsc/ucsc-giving-functionality/pull/130) and [#128](https://github.com/ucsc/ucsc-giving-functionality/pull/131) landed on 2026-08-04. What exists now:

This is what makes items 1 and 2 risky: the fund-linking logic has several branches (fund type, empty `base_url`, missing designation, non-`fund` post types, in-loop vs out-of-loop) that today can only be verified by hand.
- **PR checks.** `.github/workflows/ci.yml` runs `composer lint` and `composer test` on every pull request, across PHP 8.1 and 8.4. Previously `release.yml` only fired on tags, so nothing validated a PR at all.
- **A PHPUnit suite** — 24 tests over `ucscgiving_link_filter()` (all six branches), `ucscgiving_fund_url()`, `ucscgiving_fund_search_template()`, `ucscgiving_create_fund_search_variation()` and the two ACF JSON points.

Suggested order:
### Why the tests stub WordPress rather than run inside it

1. Add a `.wp-env.json` so contributors get a reproducible environment from the repo instead of configuring one externally.
2. Add PHPUnit with a small suite around `ucscgiving_link_filter()` and `ucscgiving_fund_url()` — the two functions that independently compute the same URL and are the most likely to drift.
3. Wire lint and tests into CI on pull requests. Today `.github/workflows/release.yml` only runs on tags, so **nothing validates a PR automatically.**
This is the constraint the first version of this section missed, and it drove the whole shape of the harness.

`ucscgiving_fund_url()` reads `get_field( 'base_url', 'option' )` — an ACF **Pro** options page, registered by the `ucsc-2022` theme rather than by this plugin. Testing it against a real WordPress install therefore needs WordPress **plus** ACF Pro **plus** the theme. ACF Pro is commercial and not on WP.org, so it cannot be installed in GitHub Actions without a licence key held as a repository secret.

`tests/bootstrap.php` supplies WordPress stand-ins instead, so the suite runs on bare PHP and Composer — no WordPress, no database, no licence, no theme, and no bearing on how anyone runs WordPress locally. It follows the dual-mode bootstrap in [`ucsc/ucsc-blocks`](https://github.com/ucsc/ucsc-blocks): set `WP_TESTS_DIR` and it uses a real WordPress test suite instead.

### No `.wp-env.json`

An earlier version of this section recommended committing one. It should not be. [`ucsc/wp-dev.ucsc`](https://github.com/ucsc/wp-dev.ucsc) — a Docker WordPress environment with HTTPS and LDAP — is already the org's shared local environment, and team members use other setups besides. A committed `.wp-env.json` would be a second, competing definition of something already solved, and the unit suite needs no WordPress anyway. Local environment choice stays a per-developer matter.

### What is still hand-verified

The suite covers functions that are pure once WordPress is stubbed. Anything needing a running WordPress still has to be checked by hand against an install with ACF Pro and the `ucsc-2022` theme active:

- block template registration and the markup under `lib/templates/`,
- the ACF JSON save/load round-trip,
- the fund-type save cycle in §1.

### Org-wide context

`ucsc-blocks` has had a PHPUnit harness for some time that **no workflow ever runs**, and no sibling repo (`ucsc-communications-functionality`, `ucsc-events-functionality`, `ucsc-news-functionality`, `ucsc-www-functionality`) has a PR check at all. `ci.yml` here is deliberately repo-local for now, and is a good candidate to promote into `ucsc/actions` — which already hosts the shared release workflow — once it has run for a release cycle.

## 4. Harden packaging and templates

- **Relative `require` in block templates.** `lib/templates/*.php` use `require 'parts/…'`, which resolves only because PHP falls back to the calling file's directory. Change to `__DIR__`-relative paths. Low effort, removes a latent break.
- **Single URL-construction path.** `ucscgiving_fund_url()` (block binding) and `ucscgiving_link_filter()` (permalink) build the same URL independently. Extract one helper so they cannot diverge.
- **Single URL-construction path.** `ucscgiving_fund_url()` (block binding) and `ucscgiving_link_filter()` (permalink) build the same URL independently. Extract one helper so they cannot diverge. Both now have characterization tests (§3), so the extraction can be made and shown to preserve behavior — this is the cheapest remaining item.

## 5. Maintenance

Expand All @@ -84,6 +105,7 @@ Suggested order:

## Non-goals

- **Integration tests against a real WordPress install.** Deliberate, not an oversight — see §3. The fund URL path depends on an ACF Pro options page registered by the `ucsc-2022` theme, so automating it in CI would mean holding a commercial licence key as a repository secret. The unit suite covers the logic; the rest is hand-verified.
- Rewriting the plugin as class-based / namespaced. The procedural structure is small and consistent; churn here would buy little.
- Registering the post type and taxonomies in PHP. `acf-json/` is the working source of truth and the ACF admin round-trips to it.
- Shipping a build step for front-end assets. The plugin ships no JavaScript, and `@wordpress/scripts` is used only for `plugin-zip`.