Micropub: articles posted as drafts (post-status: draft) are published immediately #123

Closed
opened 2026-08-22 12:04:06 +02:00 by jonny · 0 comments
Owner

Problem

iA Writer (and other Micropub clients) can mark a post as a draft via the post-status property. Our Micropub pipeline ignores this entirely — every article created via Micropub is published straight away, regardless of what the client sends.

Root cause

  • EntryData (app/Services/Micropub/Data/EntryData.php) never extracts post-status from either the JSON or form-encoded request body — there's no postStatus field on the DTO at all.
  • ArticleService::create() (app/Services/ArticleService.php) hardcodes 'published' => true on every created Article, so there's no path for a draft to land as unpublished even if the data were available.

The Article model, admin UI, and public listing (ArticlesController::index filters on published) already fully support a published flag — this is purely a gap in the Micropub ingestion path.

Expected behavior

A Micropub request with post-status: draft should create an Article with published = false. Omitting post-status, or sending post-status: published, should keep today's behavior (published = true).

Suggested fix

  1. Add a postStatus (or similar) field to EntryData::fromRequest/fromArray/toArray, reading properties.post-status.0 (JSON) / post-status (form).
  2. In ArticleService::create(), set published based on that value instead of hardcoding true.
  3. Add test coverage: Micropub article creation with post-status: draft results in an unpublished Article; with post-status: published or omitted, results in a published one.

Out of scope

Notes/bookmarks/likes don't have a draft concept today — this ticket is just about articles.

### Problem iA Writer (and other Micropub clients) can mark a post as a draft via the `post-status` property. Our Micropub pipeline ignores this entirely — every article created via Micropub is published straight away, regardless of what the client sends. ### Root cause - `EntryData` (`app/Services/Micropub/Data/EntryData.php`) never extracts `post-status` from either the JSON or form-encoded request body — there's no `postStatus` field on the DTO at all. - `ArticleService::create()` (`app/Services/ArticleService.php`) hardcodes `'published' => true` on every created `Article`, so there's no path for a draft to land as unpublished even if the data were available. The `Article` model, admin UI, and public listing (`ArticlesController::index` filters on `published`) already fully support a published flag — this is purely a gap in the Micropub ingestion path. ### Expected behavior A Micropub request with `post-status: draft` should create an `Article` with `published = false`. Omitting `post-status`, or sending `post-status: published`, should keep today's behavior (`published = true`). ### Suggested fix 1. Add a `postStatus` (or similar) field to `EntryData::fromRequest`/`fromArray`/`toArray`, reading `properties.post-status.0` (JSON) / `post-status` (form). 2. In `ArticleService::create()`, set published based on that value instead of hardcoding true. 3. Add test coverage: Micropub article creation with `post-status: draft` results in an unpublished `Article`; with `post-status: published` or omitted, results in a published one. Out of scope Notes/bookmarks/likes don't have a draft concept today — this ticket is just about articles.
jonny closed this issue 2026-08-22 18:20:13 +02:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jonny/jonnybarnes.uk#123
No description provided.