Philosophy & Architecture
WP Kernel is built on a simple but powerful philosophy: JavaScript is the source of truth, PHP is a thin contract. This guide explains the core principles, mental models, and architectural decisions that make WP Kernel a Rails-like framework for modern WordPress development.
Core Philosophy
JavaScript-First, PHP-Thin
WordPress has evolved to be JavaScript-first with Gutenberg, Script Modules, and the Interactivity API. WP Kernel embraces this evolution completely:
- JavaScript owns business logic, state management, and user interactions
- PHP provides REST endpoints, capability checks, and optional server bindings
- Bridge connects the two worlds with a single, well-defined event system
Convention Over Configuration
Like Rails, WP Kernel provides a "Golden Path" that covers 90% of use cases:
- Predictable folder structure
- Standardized naming conventions
- Automatic wiring of resources, actions, and events
- Sensible defaults with escape hatches for edge cases
The Golden Path
The Golden Path is the mental model for building with WP Kernel. Every feature follows this flow:
The Flow Explained
- UI Components trigger user interactions
- Actions orchestrate write operations (never called directly from UI)
- Resources handle data transport and caching
- Events notify other parts of the system
- Jobs process background work
- PHP Bridge provides REST endpoints and capabilities
configureKernel()
wires the registry middleware that powers this flow, exposes the typed event bus, and hands React a runtime through KernelUIProvider
. With that adapter in place the UI listens to events instead of globals, actions receive a consistent context surface, and the event catalogue stays in lockstep with the documentation you are reading now.
Core Principles
1. Actions-First Architecture
Rule: UI components NEVER call transport directly.
Why: This pattern ensures:
- Consistent event emission
- Automatic cache invalidation
- Coordinated side effects
- Testable write paths
- Audit trails for all changes
Example:
// ✗ WRONG - UI calling transport directly
function SaveButton() {
const handleSave = async () => {
await postResource.update(id, data); // Direct call
};
}
// ✓ CORRECT - UI triggering action
function SaveButton() {
const handleSave = async () => {
await UpdatePost({ id, data }); // Action orchestrates everything
};
}
2. Stable Event Registry
Rule: All events use registered names from a stable, versioned registry-no ad-hoc strings.
What "canonical" means here: Event names are predefined and versioned in a central registry. Instead of components inventing event names like
"post-saved"
or"cache-cleared"
, they import stable identifiers from@wpkernel/core/events
. This guarantees integrations won't break when event names change, and makes the event contract discoverable.
Why: This ensures:
- Stable API for integrations
- Predictable event names
- Version compatibility
- Clear documentation
Example:
// ✓ Registered event names from stable registry
events.emit('wpk.resource.post.created', payload);
events.emit('wpk.cache.invalidated', { keys: ['post', 'list'] });
// ✗ Ad-hoc event names (breaks when refactored)
events.emit('post-saved', payload);
events.emit('cache-cleared', payload);
3. Typed Resources
Rule: One resource definition creates everything you need.
Why: This provides:
- Single source of truth
- Automatic type generation
- Consistent caching strategy
- Coordinated event emission
Example:
const post = defineResource({
name: 'post',
routes: {
list: { path: '/wp/v2/posts', method: 'GET' },
create: { path: '/wp/v2/posts', method: 'POST' },
},
// Everything else generated automatically
});
// ✓ Get typed client, cache keys, events, etc.
const posts = await post.list();
const cacheKey = post.cacheKeys.list({ status: 'publish' });
events.on('wpk.resource.post.created', handler);
4. WordPress-Native Building Blocks
Rule: Build on WordPress core primitives, don't replace them.
Why: This ensures:
- WordPress compatibility
- Leverages core optimizations
- Reduces bundle size
- Future-proof architecture
Mental Models
The WordPress Data Stack
WP Kernel integrates seamlessly with WordPress's data architecture:
Action Orchestration Pattern
Actions are the conductor of the WP Kernel orchestra:
Event-Driven Architecture
Events flow through the system to coordinate behavior:
Design Decisions
Why JavaScript-First?
WordPress Evolution: Core WordPress has moved to JavaScript-first architecture:
- Gutenberg editor is React-based
- Interactivity API for front-end behavior
- Script Modules for modern JS delivery
- Block Bindings for data-driven content
Developer Experience: JavaScript provides:
- Rich ecosystem and tooling
- Type safety with TypeScript
- Modern testing frameworks
- Hot reloading and fast iteration
User Experience: Client-side rendering enables:
- Immediate feedback
- Optimistic updates
- Rich interactions
- Progressive enhancement
Why Thin PHP?
Focused Responsibility: PHP handles what it does best:
- Database operations
- Security and permissions
- Server-side rendering (when needed)
- Legacy WordPress integration
Reduced Complexity: Thin PHP layer means:
- Less context switching
- Fewer security concerns
- Easier testing
- Better performance
WordPress Compatibility: Minimal PHP footprint ensures:
- Plugin compatibility
- Theme integration
- Core update safety
- Hosting flexibility
Why Actions-First?
Consistency: Every write operation follows the same pattern:
- Predictable side effects
- Automatic event emission
- Coordinated cache invalidation
- Audit trail creation
Testability: Actions provide clean test boundaries:
- Mock at the action level
- Test orchestration logic
- Verify side effects
- Integration test confidence
Extensibility: Other developers can:
- Hook into events
- Override action behavior
- Add custom side effects
- Maintain compatibility
Real-World Benefits
For Developers
- Faster Development: Conventions reduce decision fatigue
- Better Testing: Clear boundaries and predictable patterns
- Easier Debugging: Centralized orchestration and event trails
- Team Consistency: Shared mental models and patterns
For Users
- Better Performance: Optimistic updates and smart caching
- Reliable Experience: Consistent error handling and recovery
- Rich Interactions: Modern JavaScript capabilities
- Accessibility: WordPress component library integration
For Projects
- Maintainability: Clear separation of concerns
- Scalability: Event-driven architecture supports growth
- Extensibility: Plugin-friendly event system
- Future-Proof: Built on WordPress core primitives
Common Patterns
Resource → Action → View Pattern
// 1. Define Resource
const post = defineResource({
name: 'post',
routes: { /* ... */ },
});
// 2. Create Action
const CreatePost = defineAction({
name: 'Post.Create',
handler: async (ctx, input) => {
const result = await post.create(input);
ctx.emit(post.events.created, { id: result.id });
ctx.invalidate([post.key('list')]);
return result;
},
});
// 3. Build View
function PostForm() {
const { run, status } = useAction(CreatePost);
return (
<form
onSubmit={(event) => {
event.preventDefault();
const formData = new FormData(event.currentTarget);
return run(Object.fromEntries(formData));
}}
>
{/* Form fields */}
<button type="submit" disabled={status === 'running'}>
{status === 'running' ? 'Saving…' : 'Save job'}
</button>
</form>
);
}
Event-Driven Integration
// Subscribe to canonical events
events.on('wpk.resource.post.created', (payload) => {
// Send analytics
analytics.track('Post Created', {
postId: payload.data.id,
userId: payload.meta.userId,
});
});
// PHP can mirror important events
add_action('wpk_resource_post_created', function($payload) {
// Send email notification
wp_mail($user->email, 'Post Published', $template);
});
This philosophy and architecture enable teams to build WordPress products that are maintainable, scalable, and delightful to use. By following these patterns, you get the benefits of modern JavaScript development while maintaining deep WordPress integration.