github emdash-cms/emdash @emdash-cms/admin@0.40.0

Minor Changes

  • #3364 c99bcd3 Thanks @khoinguyenpham04! - Adds bulk tagging for editors. Select posts from a collection's bulk-actions bar or paste up to 50 public links from the Tags page, review their exact titles and languages, and apply one existing or new tag. Assignments take effect immediately without publishing other draft edits, preserve existing tags, and report unmatched links or failed writes for retry.

  • #3320 840a9d3 Thanks @ascorbic! - Adds first-class blocks fields for ordered, typed page compositions. Define retained block-type versions through the schema API, MCP, or seed files; edit block cards in the admin; and render stored compositions with <Blocks value components fallback> from emdash/ui.

    Generated collection types include each retained block version, and defineBlockComponents<T>() type-checks that a component map covers every generated _type. Image, file, repeater-image, and Portable Text media inside blocks participate in normalization, MIME validation, usage tracking, and cleanup protection.

    Deploy renderer support before activating a breaking block-type version. Existing versions remain available for drafts, revisions, and stored content, and migrating a stored block to a new version requires explicit migrateBlocks: true intent.

    Sites upgrading from a release older than 0.39 must deploy 0.39 first and upgrade every runtime before creating a blocks field. The 0.39 unknown-field protection prevents an older runtime in a rolling deployment or rollback from overwriting block JSON.

  • #3167 ed51c68 Thanks @kwmr! - Adds optional link on portable-text image blocks: editor link buttons work on image selection, and Image.astro wraps images in a sanitized <a> when link.href is set. Legacy link: "https://…" strings written by WordPress/Gutenberg imports are normalised on read, so already-imported linked images keep their link and are upgraded to the object shape on their next edit.

  • #1944 bf6b0a9 Thanks @swissky! - Localizes invite, magic-link, and account-recovery emails: they now follow the site locale (falling back to the requesting user's admin language) instead of always being sent in English. Email HTML sets lang and dir on the root element, so right-to-left languages render correctly. A non-canonical site locale (pt-br) is normalized to its catalog (pt-BR); an unsupported value falls back to the requesting user's admin language.

    @emdash-cms/auth's invite and magic-link builders (buildInviteEmail, buildMagicLinkEmail, now exported) accept optional injected copy and locale via new emailStrings/emailLocale config options (InviteEmailStrings/MagicLinkEmailStrings). @emdash-cms/admin/locales exports the copy resolvers getInviteEmailStrings/getMagicLinkEmailStrings and the BCP 47 matcher matchLocale.

  • #3346 1796cd5 Thanks @ascorbic! - Adds Settings → Transfer for moving a site between EmDash installations.

    • Export: admins export the site as a .emdash package, optionally without comments, and download it. The browser fetches and checks the export file by file, so large sites download on Cloudflare Workers too; small sites can also be downloaded as one archive.
    • Import: on a site with no content of its own, admins choose a package file. The browser checks and uploads it in parts, then shows what will be imported and what the import changes, which user on this site should own each author's content (matched by email where possible), whether to keep this site's title and tagline, which starter content will be removed, and any warnings or blockers. After confirmation the import runs and ends with a verified receipt that can be copied. Leaving the page does not lose an unfinished import; an interrupted upload needs the same file chosen again. On a site that already has content, the page lists what prevents an import.
    • Approvals: the page lists requests from MCP clients to start an export or import, so an admin can approve or deny them.

    The setup wizard now asks how to start the site: with the template's sample content, as an empty site, or by importing an existing EmDash site, which replaces the "Include sample content" checkbox. Choosing import skips the sample content and opens Transfer at the import step once your account is created. While a site has no content, the dashboard shows a dismissible suggestion that links to the import, and Backups settings link to Transfer.

    When creating an API token, admins can select the transfer:export, transfer:analyze, and transfer:execute scopes to give a token, such as an agent's, narrower access than Admin, which includes them. The OAuth consent screen lists them when a client requests them.

Patch Changes

  • #3241 b8fae35 Thanks @swissky! - Fixes the General and SEO settings screens so removing the site logo, favicon, or default social image remains cleared after saving. REST, MCP, and setSiteSettings() callers can remove these media references by setting them to null; omitted settings remain unchanged.

  • #3296 1f193b2 Thanks @khoinguyenpham04! - Updates the Comments moderation page with a compact header that groups status views with search and collection filters. Status tabs use Phosphor icons with a filled active state, and empty views use a responsive standalone state instead of retaining the table shell.

  • #3348 6f1b046 Thanks @swissky! - Fixes gallery blocks seeded with $media showing empty images and losing their media on first edit. The Gallery component now renders these images, including galleries seeded with earlier versions, and the content editor previews them and keeps their media references, alt text, and dimensions when it saves. Seeding a gallery now stores each $media image as a regular gallery media reference. Galleries whose references an earlier autosave already stripped are not restored.

  • #3398 7df822b Thanks @danielmlr! - Fixes Portable Text image blocks seeded with $media, including those seeded with earlier versions, rendering with an empty src and losing their media reference when first edited in the admin or through visual editing. Seeding now stores the image as a regular media reference with its alt text and dimensions on the block, the same shape the editor saves. Blocks whose media reference an earlier edit already removed need their image selected again.

  • #3350 21ee693 Thanks @swissky! - Fixes saving from visual editing changing custom blocks identified by url, such as embeds imported from WordPress, to use id, which dropped their url. Blocks now keep the identity field they were stored with: blocks with both id and url keep both, and blocks with neither no longer gain an empty id. Custom blocks inserted in the content editor no longer gain an empty id when no ID is entered.

  • #3411 28dec10 Thanks @danielmlr! - Fixes the admin silently replacing a stored value that is not a list on the first edit to a repeater, rich text, multi-select, or blocks field, or to a repeater in a plugin block. Such values come from imports, direct database writes, or a plugin that changed a block field from a text input to a repeater. The field now shows the stored value read-only with a warning and keeps it unchanged until the editor chooses to replace it with an empty list.

  • #3284 1217386 Thanks @khoinguyenpham04! - Fixes the editor's light-mode menu highlights so slash commands, heading choices, and block transforms use a quieter neutral tint instead of the heavy interaction gray. Dark mode remains unchanged.

  • #3338 ecef5a9 Thanks @khoinguyenpham04! - Fixes cached published pages remaining stale when tag or category assignments change. Assignments still save immediately, and the editor clarifies that term changes do not wait for Publish changes.

  • #3337 ad1465d Thanks @swissky! - Fixes magic link and account recovery emails failing for recipients whose mail is scanned (for example by Microsoft 365 Safe Links). Opening the link now shows a confirmation page in the admin, and the one-time link is only used when the recipient presses Continue, so a scanner that fetches the link no longer uses it up or receives the session. Links in emails sent before the upgrade keep working.

    GET /_emdash/api/auth/magic-link/verify no longer signs in; it redirects to the confirmation page. Scripts that signed in by requesting that URL must now send POST /_emdash/api/auth/magic-link/verify with a JSON body { "token": "..." } and the X-EmDash-Request: 1 header, then keep the returned session cookie.

  • #3413 e9b70ec Thanks @danielmlr! - Fixes the Media Library Used in tab reporting no usage for a file selected as the site logo, favicon, or default social image. Those settings appear as a Site Settings result, GET /_emdash/api/media/{id}/usage lists them in a new siteSettings array, and usage.count includes them. An empty Used in tab now says "No tracked references found" and names what is not checked, such as custom rich text blocks, instead of stating that the file is not used in any content.

  • #3386 931b40d Thanks @swissky! - Fixes passkey sign-in options revealing whether an email address has an account. POST /_emdash/api/auth/passkey/options now ignores the optional email field and returns the same options for every request, so the browser offers any passkey saved for the site. The default admin login is unaffected. Clients that posted email to this endpoint to sign in with passkeys not stored on the authenticator (non-discoverable credentials, such as some older security keys) can no longer sign in with those keys. Register a passkey on an authenticator that supports discoverable credentials (most platform authenticators and current security keys), or sign in with a magic link or a configured OAuth provider. The @emdash-cms/admin PasskeyLogin component's showEmailInput prop is deprecated and no longer shows an email field; existing callers still type-check and can drop the prop. The previous email-scoped behavior cannot be restored.

  • #3323 a30b110 Thanks @emdashbot! - Fixes the default LocaleSwitcher size so its select control matches the height, corner radius, font size, and horizontal padding of adjacent Kumo Buttons. Replaces the native select chevron with an inset indicator so the right gutter is visible.

  • #3291 7a4e1fd Thanks @khoinguyenpham04! - Updates the Redirects page with a compact, accessible header that groups its title and primary action, then keeps segmented views beside their search and filter controls. The views use Phosphor icons with a filled active state. On narrow screens, the action stays beside the title, the tabs span the available width, and the two filters share one row. The layout also mirrors for right-to-left locales.

  • #3399 e4b0d81 Thanks @danielmlr! - Fixes the admin plugin registry showing "Handle unavailable" for every publisher and scrolling sideways, so verified publisher handles now appear and unresolved publisher identifiers stay inside their cards.

    A publisher whose handle no longer resolves back to its account now shows INVALID HANDLE, and installing its plugins from the registry detail page is disabled until the publisher fixes the handle. Plugins that are already installed keep running.

  • #3379 a733b90 Thanks @khoinguyenpham04! - Updates the Tags page with a searchable list, matching Add tag and Add to posts actions, and less crowded row controls. Taxonomy creation remains available from the More menu. Term forms show slug guidance on demand; term and taxonomy creation dialogs share a bordered header, scrollable body, and fixed action footer.

  • Updated dependencies []:

    • @emdash-cms/blocks@0.40.0

Don't miss a new emdash release

NewReleases is sending notifications on new releases.