Skip to content

acf-lint --wpml: check wpml_cf_preferences VALUE by field type (Layers 1-3) - #31

Merged
parisek merged 1 commit into
mainfrom
feat/30-wpml-type-value-check
Jul 25, 2026
Merged

acf-lint --wpml: check wpml_cf_preferences VALUE by field type (Layers 1-3)#31
parisek merged 1 commit into
mainfrom
feat/30-wpml-type-value-check

Conversation

@parisek

@parisek parisek commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Summary

Closes the scope of #30 (Layers 1-3 of the layered proposal; Layer 4 explicitly out of scope).

--wpml currently only checks that wpml_cf_preferences is present, plus (since 0.7.0) that image/gallery carry the right value for their location context. This extends the same idea to a type -> value check for three more field-type buckets:

  • Layer 1 (plugin fact). repeater / flexible_content must be 3. ACFML forcibly overrides both types to WPML_COPY_ONCE_CUSTOM_FIELD (= 3) at runtime regardless of the configured value — authority: ACFML\Helper\Fields::WRAPPER_FIELDS (acfml/classes/Helper/Fields.php:10) and WPML_ACF_Field_Settings::field_should_be_set_to_copy_once() (acfml/classes/class-wpml-acf-field-settings.php:335-341). Any other configured value is provably dead configuration — the message cites the plugin as authority, not doctrine.
  • Layer 2 (project doctrine, softer certainty). group should be 3 per gutenberg.md § Key Requirements ("3 only on group containers whose nested leaves carry their own preference"). ACFML does not force this one — it's a project convention. This linter has no severity/warning-level concept anywhere in src/ (checked before implementing), and adding one for a single rule would be over-engineering, so this stays inside the same --wpml findings list — the softer certainty is conveyed entirely through message wording ("doctrine, not a plugin fact") instead of a new mechanism.
  • Layer 3. accordion / tab / message are ACF UI/layout pseudo-fields holding no translatable value — only 0 or absent is valid.

Layer 4 (leaf value types — text, wysiwyg, image, link, select, url, …) is deliberately untouched. They keep only the pre-existing presence check; the 1-vs-2 split there is genuine author intent this linter doesn't second-guess.

No double-reporting

The four new buckets (repeater/flexible_content, group, accordion/tab/message) are pairwise disjoint and disjoint from image/gallery (the types the existing 0.7.0 location-context check covers) — bucketing is purely by $field['type']. A field can never be flagged by two checks at once. Verified by a dedicated test (test_wpml_image_field_gets_single_finding_not_double_reported, asserts exactly one finding) plus by construction.

Implementation

  • Reuses the exact same recursive sub_fields/layouts walker shape as the pre-existing walkFieldsWpml() — no second walker.
  • New method wpmlTypeValueFindings() + walkFieldsWpmlTypeValue() in AcfLinter, wired into lintFile() alongside the two existing --wpml checks.

Tests (TDD)

24 new PHPUnit executions across 15 new test methods (3 of them data-provider-driven with 4 cases each): every Layer-1/2/3 wrong-value + correct-value case, leaf-type non-interference (text w/ 1 and 2 stay silent), no-double-report, and a 3-level nested flexible_content -> group -> repeater recursion case.

  • Before: 162 tests / 607 assertions, all green. PHPStan: no errors.
  • After: 186 tests / 657 assertions, all green. PHPStan: no errors.
  • Delta cross-checked against git diff (15 new test_ methods, 3 with 4-case data providers = 15 + 9 = 24 — matches exactly).

Real-world validation (read-only, --wpml --strict, never --fix)

Project Before After
eprukaz2025 19 findings 19 findings (all offending fields were already fully absent — caught by the pre-existing presence check; messages reworded to be more specific, no new pointers)
pm-a 5 findings 17 findings (8 new — repeater/flexible_content/group fields wrongly set to 2)
oekoplan2024 265 findings 265 findings (same story as eprukaz — every offending field was already absent)

Manually spot-checked all 8 new pm-a findings by opening the real acf.json files — every one genuinely has repeater/flexible_content/group type with wpml_cf_preferences: 2 (not 3). No false positives found.

⚠️ Expected fleet-wide impact

Per the issue's census (1769 acf.json files fleet-wide), ~837 repeater/flexible_content fields already carry a value the plugin discards at runtime. Existing projects will very likely surface brand-new findings under --wpml --strict — this is intentional, not a regression (documented in CHANGELOG.md).

🤖 Generated with Claude Code

Extends `--wpml` from presence-only to a type -> value check for three
layers of certainty, per issue #30's layered proposal:

- Layer 1 (plugin fact): `repeater` / `flexible_content` must be `3` —
  ACFML forcibly overrides both to WPML_COPY_ONCE_CUSTOM_FIELD (= 3) at
  runtime regardless of the configured value (WRAPPER_FIELDS +
  field_should_be_set_to_copy_once()). Any other value is dead config.
- Layer 2 (project doctrine): `group` should be `3` per gutenberg.md §
  Key Requirements. ACFML does not force this one, so the message is
  worded distinctly ("doctrine, not a plugin fact") rather than adding a
  new severity subsystem for a single rule.
- Layer 3: `accordion` / `tab` / `message` (UI pseudo-fields, no
  translatable value) must be `0` or absent.

Layer 4 (leaf value types) is explicitly out of scope and untouched.
The four new buckets are disjoint from each other and from image/gallery
(the existing 0.7.0 location-context check), so no field can ever be
double-reported — verified by test and by construction (pure type-based
bucketing).

Reuses the existing sub_fields/layouts recursive walker shape rather
than building a second one.

Real-world validation (read-only, --wpml --strict, never --fix):
- eprukaz2025: 19 -> 19 findings (all offending fields were already
  absent, caught by the pre-existing presence check; messages reworded
  to be more specific)
- pm-a: 5 -> 17 findings (8 new repeater/flexible_content/group fields
  found wrongly set to 2; manually spot-checked all 8 against the real
  JSON — confirmed, no false positives)
- oekoplan2024: 265 -> 265 findings (same story as eprukaz — all
  offending fields were already absent)
@parisek parisek self-assigned this Jul 25, 2026
@parisek
parisek marked this pull request as ready for review July 25, 2026 10:55
@parisek
parisek merged commit c83f63b into main Jul 25, 2026
3 checks passed
@parisek
parisek deleted the feat/30-wpml-type-value-check branch July 25, 2026 10:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant