A developer with 10 years of WordPress plugin experience set out to replicate a basic WooCommerce-like product system on EmDash. The result took two days, not weeks. The key wasn’t coding faster — it was understanding how EmDash’s permission model changes plugin design.
Most tutorials focus on the “what” of EmDash: V8 isolates, dynamic workers, Astro integration. The non-obvious part is the capability manifest. In WordPress, a plugin implicitly gets full database access. In EmDash, you declare exactly what your plugin can touch — and the runtime enforces it.
The non-obvious insight: capabilities are not just security controls — they are documentation.
The Problem with WordPress Plugin Architecture
WordPress plugins run in the same process as the core. A product plugin can read user tables, delete posts, or send arbitrary network requests. The only barrier is trust. EmDash eliminates that trust requirement by design. But that forces developers to think differently about plugin structure.
For an e-commerce plugin, the developer needed three capabilities: read:content, write:content, and email:send. That’s it. The plugin couldn’t touch the file system, couldn’t access other plugins’ data, and couldn’t make external API calls without an explicit grant. This constraint turned out to be an advantage — it forced a clean separation between data logic and presentation.
Designing the Permission Manifest
The first hour went into the manifest file. EmDash plugins use a definePlugin function from the @emdash-cms/plugin library. The developer defined capabilities as a plain object:
“`javascript
{
capabilities: [‘read:content’, ‘write:content’, ’email:send’]
}
“`
The non-obvious insight: capabilities are not just security controls — they are documentation. Any future developer reading this manifest knows exactly what the plugin does. And because the runtime enforces them, there is no way for the plugin to overreach. You cannot accidentally create an admin user or modify another plugin’s settings.
Leveraging V8 Isolates and Dynamic Workers
Dynamic workers are the execution engine. Each plugin runs in its own V8 isolate, which spins up in milliseconds and disappears when the hook finishes. The developer used a product.created hook to trigger an email notification when a new product is published.
The non-obvious part: dynamic workers are not just for security. They also solve the cold-start problem. In WordPress, a plugin’s initialization code runs on every page load. In EmDash, the plugin only executes when the specific hook fires. For an e-commerce site with thousands of products but few admin interactions, this cuts serverless costs dramatically.
Building the Plugin: Hook Selection and Capabilities
The developer chose three hooks: product.created, product.updated, and product.deleted. Each hook triggers a dynamic worker that performs only the declared capabilities.
For example, the product.created hook reads the product data from the D1 database (via the read:content capability), formats an email, and sends it using the email:send capability. The plugin never writes to the database directly — it relies on EmDash’s built-in content type system.
The non-obvious lesson: you don’t need custom database tables. EmDash’s content types (custom post types) come with built-in field definitions, search, and SEO metadata. The developer created a “Product” content type with fields for price, SKU, and stock — all defined through the admin UI, but stored in the same D1 database. The plugin only acts on events.
Testing and Deployment
Testing a sandboxed plugin is different from WordPress. You cannot just echo debug statements — the isolate has no console output by default. The developer used EmDash’s built-in logging by requesting the log capability in the manifest. That allowed him to inspect plugin behavior during development.
Deployment took 15 minutes. The plugin was packaged as a Node module and uploaded to the EmDash admin. Because it runs in a dynamic worker, there was no server restart, no plugin conflict, no database migration. The developer rolled back by simply removing the plugin from the admin panel.
Lessons Learned
The most surprising result: the plugin took 2 days to build, but the developer estimated it would have taken 2 weeks in WordPress. The difference came from not having to write authentication, session management, or database abstraction — EmDash provides all of that. The plugin only needed to handle the business logic.
That said, this timeline is not typical for every plugin. Simple event-driven plugins with limited capabilities are fast. Complex plugins requiring external API integrations or file handling would take longer because each external interaction must be explicitly granted in the manifest. The developer avoided those complexities by keeping the e-commerce plugin self-contained.
Limitations and Considerations
The sandbox model has a tradeoff. Plugins that need to modify the core admin interface — adding custom dashboard widgets or altering the editor — cannot run in a dynamic worker. Those require a different approach: trusted Node modules that run in-process. For the e-commerce plugin, this wasn’t an issue because all product management happens through EmDash’s built-in content types.
Another limitation: the plugin cannot directly access the file system. If your e-commerce plugin generates PDF invoices, you would need to use an external storage service (like R2) and grant explicit permission. The developer skipped that feature for now.
The broader implication: EmDash’s plugin architecture naturally pushes developers toward event-driven, capability-scoped designs. That’s a good thing for security, but it requires unlearning the “full access” mindset that WordPress has normalized for 20 years.
- What is the key difference between WordPress and EmDash plugin architecture?WordPress plugins have full database access by default, while EmDash plugins must declare capabilities in a manifest, which the runtime enforces.
- How do dynamic workers benefit EmDash plugins?Dynamic workers run in isolated V8 isolates, only executing when specific hooks fire, which solves cold-start problems and reduces serverless costs.
- What capabilities did the e-commerce plugin require?The plugin needed three capabilities: read:content, write:content, and email:send.