SOLID in the WordPress Ecosystem: What 4wp.dev's Plugins Actually Prove
Introduction
WordPress makes it easy to write code that works and easy to write code that lasts, and those are not the same skill. Hooks, filters, custom post types, widgets - the platform hands you enough rope to build something maintainable or something that collapses the moment a second developer touches it. SOLID is the discipline that decides which one you get. Not as academic dogma imported from enterprise Java, but as five habits that map cleanly onto things WordPress developers already do every day. We've written up all five principles in depth on 4wp.dev/architectures/solid. This isn't a repeat of that material - it's the harder question: does our own plugin catalog actually hold up against it? Where does it, and where are we still watching ourselves?
Single Responsibility - the One We Had to Learn from Our Own Mistake
SRP says a class, a module, a plugin should have one reason to change. The honest WordPress version of this failure mode is the "kitchen sink" plugin - the one that does SEO, and a slider, and contact forms, and social icons, because it was easier to bolt features onto something that already existed than to ship something new. We named this risk directly on our own SRP page, using 4wp-bundle as the cautionary example: if it ever grew to carry responsive controls, FAQ management, Gutenberg extensions, and settings all in one codebase, that's exactly the violation.
The actual answer wasn't a paragraph of theory - it's the catalog itself:
4WP-Booking4WP-FAQ4WP Smart Link4WP Weather4WP Drive4WP Notifications
Each is a separate plugin with a separate reason to change, sharing only infrastructure through 4wp-bundle, not features. That split isn't a marketing decision. It's SRP applied at the product level, not just the class level, and it's the reason a bug in the booking flow can never be a reason to redeploy the FAQ registry.
Open/Closed - the Principle WordPress Ships for Free
OCP - open for extension, closed for modification - is arguably the one principle WordPress gets right by default. do_action() and apply_filters() are OCP in procedural form: WooCommerce alone ships 700+ action hooks and 400+ filter hooks, and its whole extension ecosystem exists without a single third party editing WooCommerce's own source.
Our own clearest example is 4WP-Booking. The plugin was built around a provider contract from day one - Clinic Cards today, Google Calendar and Calendly on the roadmap - specifically so that adding a new booking provider is an extension, not a rewrite. Nothing in the booking domain has to change for a new provider to plug in behind the same contract. That's the same shape as a hook, just at the architecture layer instead of the callback layer.
Liskov Substitution - the One That's Easiest to Fake and Hardest to Actually Keep
LSP requires that anything substitutable for a base type actually behaves like it - same contract, no surprise exceptions, no broken assumptions. WordPress breaks this constantly: a WP_Widget subclass that throws where the parent returns cached output, a custom post type wrapper that crashes on get_permalink(). The interface looks satisfied. The behavior isn't.
4WP Smart Link is our sharpest internal test of this, even though it's a runtime pattern rather than a class hierarchy - worth being precise about, since LSP is usually framed as inheritance. The plugin decides between two modes:
- Anchor mode - wrap the block in
<a> - Host mode - attach the click via
data-forwp-smart-link-url
depending on whether inner interactive elements need to keep priority. Whichever mode fires, the outward contract - "this block is now clickable, and its inner links still work" - holds identically. Nothing downstream needs to know which mode ran. That's the substitutability guarantee LSP is actually protecting, applied to a strategy choice instead of a class swap.
Interface Segregation - Don't Make Every Plugin Implement Methods It'll Never Use
ISP says no client should depend on methods it doesn't use. Our own page frames this well for Gutenberg:
- A simple Quote block only needs to render.
- A Cover block needs render, transform, and style variations.
Forcing both through one bloated block contract is the violation, and forcing a lightweight SEO plugin to implement Has_Cron because some other plugin needs scheduled tasks is the same mistake at the plugin level.
4WP-FAQ is the clean version of this: the registry (the FAQ entry itself, as a CPT) doesn't know or care how it's displayed, and the two display blocks - 4WP FAQ List and 4WP FAQ Card - each consume only what they need from the registry, not a shared monolithic "FAQ manager" interface that both would have to partially ignore.
Dependency Inversion - the One That Makes the Roadmap Possible
DIP says high-level modules should depend on abstractions, not concrete implementations - a Mailer_Interface instead of a hard-coded wp_mail() call, so you can swap providers without touching business logic. This is, again, 4WP-Booking's core architectural bet. The booking domain doesn't depend on Clinic Cards - it depends on a provider contract that Clinic Cards happens to implement first. That's the entire reason Google Calendar and Calendly can be added later as roadmap items instead of rewrites.
DIP isn't an abstraction for its own sake here; it's the specific mechanism that turns "add a new integration" from a risk into a scheduling decision.
Where This Actually Lands
SOLID overlaps with itself constantly - Booking's provider contract is simultaneously an OCP and a DIP story, and that's not sloppy analysis, it's what these principles look like when they're actually load-bearing instead of decorative.
The honest version of this article isn't "we nailed all five" - it's that four of the five show up as deliberate architecture in shipped plugins, and the fifth (SRP) shows up as a mistake we named on our own site before we fixed it in the catalog. That's the difference between citing SOLID and being accountable to it.
Full breakdowns of each principle, with more WordPress-specific examples and common violations: 4wp.dev/architectures/solid.
Comments
No comments yet. Start the discussion.