Proof of Concept - On-page frontend editing for Craft CMS powered by DataStar.
Smoke enables content editors to edit Craft CMS entries directly on the frontend of your website using a lightweight, reactive interface powered by DataStar.
- Inline Editing Panel: Slide-out panel with all editable fields
- Field Type Support:
- β Plain Text
- β Rich Text (CKEditor) - basic textarea for now
- β Lightswitch
- β Dropdown
- β Table
- π§ Assets (display only)
- π§ Entries/Categories/Tags/Users (display only)
- π§ Matrix (display only)
- Permission Aware: Only shows edit controls to authorized users
- Mobile Responsive: Works on all screen sizes
- Keyboard Shortcuts: ESC to close, Cmd/Ctrl+S to save
- Full CKEditor integration for rich text
- Asset selector with upload
- Relationship field pickers (entries, categories, tags, users)
- Matrix block editing and reordering
- Auto-save and draft support
- Revision history
- Multi-language support
- Live preview updates
Add the GitHub repository to your project's composer.json:
"repositories": [
{
"type": "vcs",
"url": "https://github.com/justinholtweb/smoke"
}
]composer require justinholtweb/smokeOr if using DDEV:
ddev composer require justinholtweb/smokephp craft plugin/install smokeOr with DDEV:
ddev craft plugin/install smokeAdd the following to your main layout template (e.g., templates/_layout.twig):
{# Initialize Smoke editor - this automatically injects the editor container #}
{% do smoke.init() %}In your component templates, wrap editable content with the smoke.editable() function:
{# Example: Making a text field editable #}
<h1 {{ smoke.editable(entry, 'title')|raw }}>
{{ entry.title }}
</h1>
<div {{ smoke.editable(entry, 'bodyContent')|raw }}>
{{ entry.bodyContent }}
</div>{# In your template #}
<div class="content">
<h1 {{ smoke.editable(entry, 'heroHeading')|raw }}>
{{ entry.heroHeading }}
</h1>
<div {{ smoke.editable(entry, 'description')|raw }}>
{{ entry.description }}
</div>
</div>A floating "Edit Page" button will appear for logged-in users with edit permissions. Clicking it opens the edit panel with all editable fields.
- ESC - Close edit panel
- Cmd/Ctrl + S - Save changes
- DataStar Integration: Uses DataStar for reactive updates without heavy JavaScript frameworks
- SSE Responses: Server sends HTML fragments via Server-Sent Events
- DOM Morphing: Updates only changed parts of the page
- Permission-Based: Respects Craft's built-in permission system
vendor/justinholtweb/smoke/
βββ src/
β βββ Plugin.php # Main plugin class
β βββ controllers/
β β βββ EditController.php # Handles edit panel requests
β β βββ SaveController.php # Handles save operations
β βββ services/
β β βββ SmokeService.php # Core editing logic
β βββ variables/
β β βββ SmokeVariable.php # Twig template API
β βββ assetbundles/
β β βββ smoke/
β β βββ SmokeAsset.php
β β βββ dist/
β β βββ smoke.css # Editor styles
β β βββ smoke.js # Frontend interactions
β βββ templates/
β βββ _components/
β β βββ edit-panel.twig # Main edit UI
β β βββ editor-container.twig # Container template
β βββ _field-editors/
β βββ plaintext.twig # Field-specific editors
β βββ richtext.twig
β βββ lightswitch.twig
β βββ ...
βββ composer.json
Initializes the Smoke editor (loads DataStar and assets).
{% do smoke.init() %}Check if the current user can edit an entry.
{% if smoke.canEdit(entry) %}
<button>Edit</button>
{% endif %}Generate editable attributes for a field.
<div {{ smoke.editable(entry, 'myField')|raw }}>
{{ entry.myField }}
</div>Generate an edit button.
{{ smoke.editButton(entry, {
label: 'Edit Page',
class: 'my-custom-class'
})|raw }}- PHP 8.2+
- Craft CMS 5.4+
- Log in to Craft CMS
- Visit any entry page on the frontend
- Look for the floating "Edit Page" button
- Click to open the edit panel
- Make changes and save
Override Smoke's styles by adding custom CSS after the asset bundle:
.smoke-edit-btn {
background: your-brand-color;
}To add support for a new field type:
- Add the field class to
SmokeService::isFieldTypeSupported() - Map it in
SmokeService::getFieldEditorType() - Create editor template:
templates/_field-editors/{type}.twig - Create display template:
templates/_field-editors/{type}-display.twig
- Ensure you're logged in with edit permissions
- Check that
smoke.init()is called in your layout - Verify the editor container is included
- Make sure
smoke.editable()attributes are added - Check that the field type is supported
- Verify the field exists in the entry's field layout
- Check PHP error logs
- Ensure the field handle is correct
- Verify you have permission to edit the entry
- Check for validation errors
- Built with DataStar
- Inspired by Craft DataStar Plugin
MIT
See GitHub Issues for planned features and known bugs.
Note: This is a proof of concept. Use in production at your own risk. Contributions welcome!