Pointing SAMA v2 at a real WordPress plugin in the wild

Earlier today I published /sama/v2/example-wordpress — a hypothetical event-registration plugin laid out under the v2 discipline. Hypothetical examples are easy: you design the layers and then describe a codebase that fits them. The harder question is what v2 sees when you point it at code that wasn't designed under any layer discipline at all.

So I picked one. Open Graph and Twitter Card Tags by WPExperts (the plugin formerly known as Wonderm00n's, slug wonderm00ns-simple-facebook-open-graph-tags) — 200k+ active installs, ten-plus years of git history, the canonical "small useful plugin" shape that WordPress is full of. Downloaded the latest release (v3.4.0), unzipped, walked the source.

This isn't a takedown. The plugin works. It ships. It does exactly what its name says. The question this post answers is: if a PHP-aware SAMA v2 verifier existed, what would it report against this codebase?

#What's actually in the box

Total: 6,445 lines of PHP across 17 source files (excluding the WordPress index.php security stubs and the vendored Post-SMTP-recommendation library).

The architecture, at a glance:

wonderm00n-open-graph.php                                 83 lines   # WP entry — header, includes, uninstall hook
fbimg.php                                                224 lines   # standalone helper (referenced from a URL)
includes/
  class-webdados-fb-open-graph.php                       674 lines   # CORE: hook registration, options loading
admin/
  class-webdados-fb-open-graph-admin.php                 784 lines   # ADMIN: settings save, FB debug call
  options-page-facebook.php                              556 lines   # admin UI tab (HTML + HTTP + JSON parsing)
  options-page-general.php                               486 lines   # admin UI tab
  options-page-3rdparty.php                              386 lines   # admin UI tab
  options-page-schema.php                                261 lines   # admin UI tab
  options-page.php                                       246 lines   # admin UI wrapper
  options-page-twitter.php                               188 lines   # admin UI tab
  options-page-seo.php                                   123 lines   # admin UI tab
  options-page-right.php                                  73 lines   # admin UI sidebar
  options-page-tools.php                                  51 lines   # admin UI tab
  options-page-recommend-post-smtp.php                    34 lines   # admin UI tab
public/
  class-webdados-fb-open-graph-public.php              1,554 lines   # PUBLIC: the actual og:* + twitter:* + schema rendering

Three god-classes (core, admin, public), each owning a vertical slice of feature work end-to-end. Around them, eleven options-page-*.php files that mix HTML, business logic, HTTP, and JSON parsing in the same callback. No layer separation, no test files anywhere in the source (zero *test*.php files in the entire archive).

This is normal WordPress. Most plugins in the directory look like this.

#What the v2 verifier would report

Walking each of the seven §4 conformance checks against what's in the source:

##1 Sorted

Every file carries a profile-recognised prefix; lexicographic prefix order equals layer order.

The plugin has no prefix scheme at all. File names follow class-vendor-feature-area.php and options-page-tab.php patterns; their alphabetical sort has no relation to architectural layer. Would fail on every non-index source file.

##2 Architecture

Every file maps to exactly one canonical layer; no file is unprefixed or maps to two layers.

Without a profile mapping any prefix to a canonical layer, every file would be flagged unprefixed. Even if we tried to retrofit a profile — say class-*-public.php → Layer 1, class-*-admin.php → Layer 1 — the single file behind that pattern does enough Layer 2 work (HTTP, DB, JSON parsing) that the mapping wouldn't be honest.

##3 Modeled (tests)

Every Layer 1 and Layer 2 behavior file has a sibling test file.

Zero test files in the archive. The plugin has no unit tests at all — grep -r 'PHPUnit\|TestCase' /tmp/wonderm00ns-* returns nothing. Would fail the moment any source file is mapped to Layer 1 or 2.

##4 Modeled (boundary)

External input is parsed only in Layer 2.

This is where it gets interesting. Boundary patterns are scattered, not localised:

  • HTTP outboundwp_remote_get(...) lives in admin/class-webdados-fb-open-graph-admin.php:464 (calling Facebook's Graph debug API) AND in admin/options-page-facebook.php:307 (calling Facebook's translation XML) AND in public/class-webdados-fb-open-graph-public.php:1301 (fetching remote images). Three different files, three different layers conceptually.
  • JSON parsingjson_decode lives in admin/class-webdados-fb-open-graph-admin.php:475 AND admin/options-page-facebook.php:364. Mixed with HTML output in the second case.
  • Filesystem readsfile_get_contents() against a bundled XML file in admin/options-page-facebook.php:339. Same file mixes this with HTTP, JSON parsing, and direct HTML echoing.
  • Superglobals43 raw $_POST / $_GET / $_REQUEST accesses across the codebase. Most of them in admin classes, but the pattern is "wherever a hook needs to read the request, just touch the superglobal directly."

A boundary-ratio metric here would be near-zero: parsing happens almost anywhere except in a dedicated adapter layer (because there isn't one).

##5 Atomic

No file exceeds the line cap (default ~700; profile may lower, never raise). No barrel re-export files.

Three files over the 700-line cap:

  • public/class-webdados-fb-open-graph-public.php1,554 lines (220% of cap)
  • admin/class-webdados-fb-open-graph-admin.php784 lines (112%)
  • includes/class-webdados-fb-open-graph.php — 674 lines (just under, but close)

The 1,554-line public class is a textbook example of what §4.5 was written to prevent. Inside that one file: OG tag generation, Twitter Card generation, Schema.org JSON-LD generation, image URL resolution, image dimension caching, remote image fetching via wp_remote_get, WooCommerce product handling, multilingual locale logic, third-party SEO plugin compatibility (Yoast, AIOSEO), and the WP filter callbacks that wire it all up. Each of those is a sublayer or a separate file under v2.

##6 The Law (§1.2)

Imports always point to a strictly lower layer number — never upward, never sideways across a higher number, never cyclic.

PHP require_once does exist as an import edge, but without a profile mapping the verifier has nothing to check against. The architectural spirit of §1.2 — that lower concerns shouldn't reach into higher ones — is violated structurally: the entry file itself (wonderm00n-open-graph.php) contains direct $wpdb->query("DELETE FROM ...") calls in the uninstall hook. The Pure layer doesn't exist; the Adapter layer is everywhere.

##7 Consistency (§3)

No file's imports contradict its declared layer.

Vacuous — there are no declared layers to contradict.

Summary score: 0 of 7 checks would pass. Which is not surprising and not the point. The plugin wasn't built under v2; you can't grade an essay against rules its author never opted into.

#Estimated §5 metrics

A PHP-aware metrics emitter doesn't exist yet, but the values can be estimated by hand against the operational definitions on /sama/v2 §5:

metric this plugin (estimated) tdd.md (measured)
graphDepth ~3 (entry → core → public/admin classes; very flat, almost no transitive depth) 7
boundaryRatio <10% (no dedicated adapter sublayer — parsing is spread across admin classes, UI pages, the entry file, and the public class) 100%
workingSetFit (50 ≤ LOC ≤ 500) ~47% (8 of 17 non-index source files in the sweet spot; three big god-classes drag it down) 80%
violationCounts (sum) 17+ Atomic, dozens of boundary, ~17 Architecture 0

The interesting comparison isn't ✓ vs ✗ — that's the compliance score §5 explicitly tells us not to lead with. The interesting comparison is the delta on the same metric axes. Compliance proves the rules were followed; the delta is the variable that proves whether following them was worth the cost.

#What v2 makes visible that the existing code hides

Three architectural facts the v2 lens surfaces:

1. The 1,554-line public class is doing seven jobs at once. Under v2, the rendering of og:* tags, Twitter Cards, Schema.org JSON-LD, image-URL resolution, third-party SEO compatibility, and WooCommerce-specific behaviour would each live in their own Core (b*_) file with a sibling test. Today, changing one of them risks touching all of them, and there's no test fixture to catch a regression. A PR review on this file is essentially trust-based — the LOC budget is too big to read end-to-end.

2. The 43 superglobal accesses mean every change to a settings field is a hand-traced refactor. Without a c3_* controller sublayer that owns "how a settings POST becomes a typed value," the validation logic is duplicated across options-page-*.php files. An agent asked to add a new settings option has to find every place the related field is touched. v2's boundary rule reduces that to one file by construction.

3. $wpdb inside the entry file (uninstall hook). Under v2 this is c1_* work in an adapter file with a sibling test that asserts what gets deleted. Today it's an inline closure that runs once per uninstall, no test, and a future change to the schema requires editing a string literal inside a wp_* function. The Law check would catch this in v2 land; under stock WP idioms there's nothing to push back.

#The honest interpretation

A v2-aware reviewer looking at this plugin doesn't conclude "this code is bad." They conclude:

  • The plugin is shaped exactly like WordPress's official patterns push you to shape it. WP teaches: register hooks at the top, do work in their callbacks, use $wpdb when you need to read or write data. There is no built-in pressure toward layer separation; in fact, the add_action / add_filter inversion-of-control pattern actively encourages mixing wiring with logic.
  • 0 of 7 checks passing is the expected baseline for code written under WP idioms with no external discipline. Most plugins in the repository score the same. That's not a SAMA failure — that's the data point that lets us measure the delta if we ever do build a plugin under v2 from scratch.
  • The PR that this post would generate — if I'd been the maintainer — wouldn't be "refactor everything." It would be one specific extraction: pull the 1,554-line public class apart into seven files of 200-300 lines each, each with a sibling unit test. The §5 metrics would shift measurably on that one refactor; the user-facing behaviour wouldn't change at all.

#What this exercise actually buys us

Now there are two profile snapshots in the world: this site's own tdd-md profile (TypeScript, scoring 7/7 ✓ on §4 with graphDepth=7, boundaryRatio=100%, workingSetFit=80%), and this hand-estimated WordPress plugin (PHP, scoring 0/7 with graphDepth≈3, boundaryRatio<10%, workingSetFit≈47%).

That's still only n=2 and across different languages, so it's a long way from "v2 is empirically worth following." But it's the first data point where a real codebase that was not designed under v2 gets measured on the same axes. Future work — a v2-discipline plugin built from scratch, or a real refactor of one of the god-classes here — would let the delta speak for itself.

The chain extended one more link today: from "here is the spec and a hypothetical worked example" to "here is the spec, here is what a real plugin in the wild looks like through this lens, here is what the §5 metrics would say if a PHP-aware verifier existed." The PHP-aware verifier itself is the next piece of cable.


See for yourself: