Install
- Download the zip and unpack it. Inside is
pluma.php. - Upload
pluma.phpto the folder that holds yourindex.html(by FTP, SFTP or your host's file manager). Not a subfolder: PlumaEditor edits the pages in the folder where it is. - Straight away, open
https://your-site.com/pluma.phpand choose a password of at least 10 characters. Whoever opens the page first sets the password, so don't leave it for later.
That's it. PlumaEditor creates two folders next to your pages:
| Folder | What it holds | Public? |
|---|---|---|
.pluma/ |
password hash, settings, the history of every page | No: every data file returns nothing when requested |
pluma-media/ |
the images you upload, already optimised | Yes: your pages show them |
Don't delete either of them while you use PlumaEditor.
Requirements
- PHP 8.1 or newer, with the
gdandmbstringextensions (almost every host has them). - PHP must be allowed to write in the site folder. If you uploaded the files as another user (for example as root over SSH), give them back to the site's user.
- Apache or Nginx. No database, no
.htaccessneeded.
If something is missing, the first screen says what, in plain words.
Try it on your computer first
php -S localhost:8000
Run this in a copy of your site folder with pluma.php in it, then open http://localhost:8000/pluma.php.
Editing
- Text: click a heading or a paragraph and type. Bold, italic and links work in paragraphs.
- Links: click a button or a link to change its text, its address (a page of the site, a web address, an email or a phone number) and whether it opens in a new tab.
- Images: click an image to upload a new one or pick one you uploaded before, write its description, and choose the focal point that must stay visible when the layout crops it.
- Video: click a YouTube or Vimeo video and paste a new link.
- Blocks: hover a card, team member, event or list item, then duplicate, move or delete it from the small bar above it.
- Page settings: the page icon in the top bar sets the title, the description and the image shown when the link is shared.
- New page: the + next to the page list creates a copy of the current page.
Press Save (or Ctrl+S). Undo with Ctrl+Z while you edit; restore older versions from History.
Updating and removing
- Update: replace
pluma.phpwith the new version. Your password, history and images are kept. - Forgot the password: delete
.pluma/config.phpwith your file manager or FTP and openpluma.phpagain to set a new one. History and images are kept. - Remove: delete
pluma.phpand the.plumafolder. Keeppluma-media/: your pages use the images in it.
Preparing a site
PlumaEditor works on any HTML page, but a page prepared for it gives the person editing exactly the freedom they need — no more, no less. Preparing a page means adding a few data-pluma attributes.
As soon as a page has one data-pluma attribute, it switches to marked mode: only marked elements are editable.
Attributes
| Attribute | Values | Effect |
|---|---|---|
data-pluma |
text |
Plain text: no formatting, Enter is blocked. For headings, buttons, labels. Existing inline markup (like an accent <span>) is kept. |
data-pluma |
rich |
Text with bold, italic and links. On a container (div, section, article…) Enter creates new paragraphs. |
data-pluma |
image |
On an <img>: replace the image and edit its description. |
data-pluma |
bg |
Background image set in the element's style="background-image: url(…)". |
data-pluma |
link |
On an <a>: edit the link text, address and "open in a new tab". |
data-pluma |
video |
On a YouTube or Vimeo <iframe>: replace the video by pasting a link. In automatic mode, YouTube and Vimeo players are found without marks. |
data-pluma-shared |
name | A part repeated on several pages (header, menu, footer). Edited on one page, saved on all pages that have a part with the same name. |
data-pluma-label |
text | Friendly name shown in the editor ("Team photo"). |
data-pluma-id |
[A-Za-z0-9_-] |
Optional stable name for the element. |
data-pluma-ignore |
— | Excludes the element and everything inside it (also in automatic mode). |
data-pluma-repeat |
optional name | Marks a block that can be duplicated, moved and deleted. Put it on each item (each card, each event). Neighbouring items with the same tag and the same name form one group. |
The attributes stay in the published HTML. Browsers and search engines ignore them.
Example
<section class="hero" data-pluma="bg" style="background-image: url('img/hero.jpg')">
<h1 data-pluma="text">Festival Subversivo 2027</h1>
<div class="intro" data-pluma="rich">
<p>Four nights of <strong>strange</strong> films.</p>
</div>
<a class="button" href="programme.html" data-pluma="link">See the programme</a>
</section>
<img data-pluma="image" data-pluma-label="Poster" src="img/poster.jpg" alt="Festival poster" width="400" height="550">
Blocks
Blocks are repeated parts of a page: cards, team members, events, slides, list items.
- With marks: as soon as a page has one
data-pluma-repeat, only marked items are blocks. A single marked item is enough (for example, the only event so far); the person editing can duplicate it. - Without marks: PlumaEditor looks for runs of sibling elements with the same tag and the same classes, side by side, that contain something editable — three
<li class="card">, two<figure>, rows of a table.
<section class="events">
<article class="event" data-pluma-repeat="event">
<h3 data-pluma="text">Opening night</h3>
<p data-pluma="rich">12 March, 21:00 — Teatro Académico</p>
</article>
<article class="event" data-pluma-repeat="event">
<h3 data-pluma="text">Closing gala</h3>
<p data-pluma="rich">15 March, 21:30 — Convento São Francisco</p>
</article>
</section>
Rules worth knowing:
- Items of a group must sit side by side, with nothing but spaces or comments between them.
- Blocks don't nest: when a block contains another group (a section with a list of cards), the inner group wins.
- The last item of a group can't be deleted, so there is always one left to duplicate.
- Content that a script generates at runtime is not a block. Sliders that clone their slides are fine: PlumaEditor edits the real slides.
Shared parts
Mark the header, menu or footer that every page repeats:
<header class="site-head" data-pluma-shared="header">
<a href="index.html" data-pluma="link">Northlight Films</a>
<nav>
<ul>
<li data-pluma-repeat="menu"><a href="index.html" data-pluma="link">Home</a></li>
<li data-pluma-repeat="menu"><a href="about.html" data-pluma="link">About</a></li>
</ul>
</nav>
</header>
- Put the same mark, with the same name, on every page.
- Saving copies the part, exactly as it is on the page you edited, to every other page with that name. Each page keeps a copy of its previous version in the history.
- Relative links are adjusted for pages in subfolders:
about.htmlbecomes../about.htmlinblog/post.html. - In automatic mode, links inside a shared
<nav>become editable (other navigation stays untouched).
Good practice
- Mark the content, not the layout: the words, the pictures, the call-to-action links.
- Put
widthandheighton images. PlumaEditor keeps the proportions right when an image is replaced. - Mark menus and footers with
data-pluma-sharedso they stay identical on every page. - Give each page a
<title>and a<meta name="description">; PlumaEditor adds the sharing tags when you set them in Page settings. - Content that a script generates at runtime can't be edited — PlumaEditor edits the HTML file, not what scripts build.
Prompt for AI tools
Paste this at the end of your request when you ask an AI tool (Claude, or any other) to build a site:
Make the site editable with PlumaEditor. Use plain static HTML files (no build step, no framework that renders content with JavaScript). Mark editable content with these attributes: -
data-pluma="text"on headings, button labels and short labels; -data-pluma="rich"on paragraphs, and on containers whose paragraphs may grow (the container holds the<p>elements); -data-pluma="image"on content images, always withwidth,heightand a meaningfulalt; -data-pluma="bg"on elements with a content background image, set inline asstyle="background-image: url('…')"; -data-pluma="link"on call-to-action links; -data-pluma-label="…"with a short human name on images and important blocks; -data-pluma="video"on YouTube or Vimeo<iframe>embeds; -data-pluma-shared="header"anddata-pluma-shared="footer"on the header (with the menu) and the footer, identical on every page; mark the menu links withdata-pluma="link"and each menu item withdata-pluma-repeat="menu"; -data-pluma-repeat="…"on every item of repeated content (each card, team member, event, testimonial, slide), with the same name for items of the same kind. Items of one kind must be siblings, side by side. Do not mark navigation menus, footers, forms or decorative elements. Keep text in the HTML, not injected by scripts.
Security
- The password is stored with Argon2id (bcrypt where Argon2id is missing). Five failed sign-ins from one address in 15 minutes lock that address out for 15 minutes.
- The session is a signed,
HttpOnly,SameSite=Strictcookie. Signing out ends every session. - Every change carries a token and is checked against the page's own address.
- Only
.htmland.htmfiles inside the site folder can be opened or written. - Everything typed is cleaned on the server: scripts, event handlers,
styleattributes andjavascript:links never reach your pages. - Uploads are checked by their content and re-encoded; SVG files are refused.
- A page is written only after a copy is in the history and the result passes a structural check.
Know the limits of version 0.3: whoever opens pluma.php first sets the password; old versions in .pluma/history/ have random names, but a server that serves hidden folders could expose them to someone who guesses a name; your site's own scripts run inside the editor, so only include scripts you trust.
Found a vulnerability? Please write to security@plumaeditor.com instead of opening a public issue.