golchha / wp-plugin-boilerplate
An opinionated, OOP-first WordPress plugin boilerplate for building long-lived, maintainable plugins.
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
Type:wordpress-plugin
pkg:composer/golchha/wp-plugin-boilerplate
This package is auto-updated.
Last update: 2026-02-04 10:00:14 UTC
README
An opinionated, OOP-first WordPress plugin boilerplate for building long-lived, maintainable plugins.
This repository is a foundation, not a demo plugin.
Core Principles
1. One entry point
wp-plugin-boilerplate.phpis the only file WordPress directly interacts with- No logic lives there beyond wiring
2. Centralized hooks only
add_actionandadd_filterare allowed only insideLoader- All hooks must be registered via
$loader->action()or$loader->filter()
3. No WordPress globals in business logic
- No
$_POST,$_GET, or$_REQUESToutside controlled entry points - No scattered
global $wpdb
4. Extend by adding classes, not editing core
- New behavior = new class
- Core orchestration classes should rarely change
5. PSR-4 is non-negotiable
- File name = class name
- Namespace = folder structure
- Case-sensitive, always
6. Tabs are first-class concepts
- Admin screens are composed of tabs
- Tabs may be:
- settings tabs (persist data)
- presentation-only tabs (About, Help, Docs)
- Not all tabs save data, by design
7. Settings are schema-driven and isolated
- Each settings tab owns its own schema
- Each settings tab persists data under its own option key
- Defaults are defined centrally in schemas
- Raw
get_option()usage outside the settings layer is forbidden
8. Multisite is explicit, never implicit
- Multisite is supported, but never assumed
- Each settings schema explicitly declares its storage scope:
site→ per-site optionsnetwork→ network-wide options
- Network-scoped settings are visible and editable only in Network Admin
- There is no automatic switching between
optionandsite_option
Folder Responsibilities
| Folder | Responsibility |
|---|---|
src/ |
All PHP source code |
src/Admin |
Admin-only behavior |
src/Public |
Frontend behavior |
src/Support |
Shared helpers and infrastructure |
assets/ |
JS / CSS |
languages/ |
Translations |
Documentation
This boilerplate is intentionally opinionated and schema-driven.
-
HOW-TO-USE.md
Practical guidance on creating a real plugin using this boilerplate. -
FIELDS.md
Complete reference of all supported field types, their syntax, and guarantees.
Advanced internal topics such as multisite behavior, schema migrations, and import/export are documented separately to keep this README focused.
See: Advanced Topics
Settings Architecture
TabContractdefines navigation and renderingSchemaContractdefines persistence, defaults, and sanitizationSettingsTabContractexplicitly marks tabs that own settings
Rules:
- Tabs render content only
- Tabs never render
<form>tags or action buttons - UI chrome (forms, buttons, notices) is owned by the renderer
- Presentation-only tabs must never touch settings storage
What NOT to do
- ❌ Put logic in the entry file
- ❌ Call
add_actionoradd_filterdirectly in feature classes - ❌ Access
get_option()/get_site_option()outside the settings repository - ❌ Run migrations on plugin activation
- ❌ Introduce silent side effects in constructors
Mental Model
- Entry file = handshake
- Plugin = orchestration
- Loader = wiring
- Classes = behavior
If you break these rules, this stops being a boilerplate.
Changelog
Please see CHANGELOG for more information on recent changes.
Security
If you discover any security-related issues, please email vardhans@ulhas.net instead of using the issue tracker.
Author
- Ulhas Vardhan Golchha — Initial work
See also the list of contributors.
License
If this boilerplate has been useful to you, you can support its development here:
Buy me a coffee