Etch Font Manager
Manage self-hosted fonts inside the Etch builder. Install Google Fonts locally, convert uploads to WOFF2, test variable axes, publish typography tokens, and control delivery.
by donkanishka · github.com/donkanishka/etch-font-manager · website
Install
The author publishes release zips, so WP-CLI can install straight from GitHub:
wp plugin install https://github.com/donkanishka/etch-font-manager/releases/download/v1.0.2/etch-font-manager.zipDeclares an update source (https://github.com/donkanishka/etch-font-manager), so updates arrive through the plugin's own updater.
Readme
Etch Font Manager
Manage self-hosted custom fonts inside the Etch builder. No trips back to the WordPress dashboard.

The plugin registers a Font Manager control in the Etch Settings Bar using Etch's official Controls API and opens a docked panel that follows the builder's own panel conventions (sizing, tokens, typography, focus styles, light/dark scheme).
Features
- Native Settings Bar control — registered through
window.etchControls.builder.settingsBar, grouped with Etch's own managers at the end of the top section. - Full-screen manager — mirrors Etch's native manager pattern (Content Hub, Style Manager, Asset Manager): a takeover surface beside the settings bar, a 40px header and a 256px inner navigation column, all built from Etch's own design tokens so it follows the builder's colour scheme.
- Specimen-first browsing — Library and Google Fonts render in your choice of Row or Grid, with editable preview text, a 14-72px size slider, and each family previewed in its own script rather than a Latin pangram (Google Fonts prefers Latin, since a search page mixes scripts by nature).
- Upload fonts — drag and drop
.woff2,.woff,.ttf,.otffiles. A file already in the library, including a convertible original whose WOFF2 twin you already hold, is refused before it is even sent. - Built-in WOFF2 converter — drop a
.ttf,.otfor.woffand it is converted to WOFF2 before it is uploaded. Source Code Pro goes 205 KB → 72 KB from TTF and 128 KB → 74 KB from OTF; WOFF saves less (17-23%) because it is already compressed. WOFF is unwrapped back to sfnt with the browser's ownDecompressionStreambefore compressing, which is byte-exact and needs no extra download. Files already on the server can be converted from the Uploaded files list, with every family variant repointed at the new file automatically. It runs entirely in your browser —google/woff2compiled to WebAssembly, in a Web Worker — so no font is ever sent to a third-party service. The conversion is lossless: variable axes, named instances and OpenType features are carried through untouched. It is not a subsetter. The same WebAssembly module also decodes a WOFF2 just far enough to read itsfvartable, which is how an uploaded variable WOFF2 gets working axis sliders without ever leaving your browser. - Google Fonts — search, filter by category or writing system, sort, and one-click install. Files are downloaded locally, so the frontend makes no requests to Google.
- Subset support — choose which subsets to download (latin, latin-ext, sinhala, tamil, cyrillic, greek, vietnamese and so on). Each
@font-facegets a matchingunicode-range, so browsers only fetch the scripts a page actually uses. A family's own script is preselected alongside latin, so installing e.g. Noto Sans Sinhala from a single click does not silently produce a font with no Sinhala glyphs. - Filename detection — weight and style are read from uploaded file names (
Inter-SemiBoldItalic.woff2,Roboto-300.woff2) and applied when the file is mapped. - Variable font support — axes are read straight from the file, including a WOFF2. A tester lets you tune an instance per family; the chosen
font-variation-settingsvalue is written into the family's own CSS and is what the site actually renders, not the default cut. - Typography tokens — publish a family as the site's heading or body font under the
--heading-font-family/--text-font-familycustom properties Etch documents and Automatic.css reads, so a framework picks it up without you writing a rule. Each token belongs to exactly one family at a time. - Delivery controls — per-family
font-display, a preload toggle for the cut a page renders first, a fallback stack, anApply toselector list, and an optional metric-matched local fallback face that holds the line height steady while the real font loads. - Enable, disable and trash — switch a family off without deleting it (no
@font-face, no custom property, no preload, but files and mapping are kept), or move it to a trash you can restore from. Deleting permanently drops the record only; font files are always removed by a separate explicit action, and are never touched at all when the plugin itself is deleted unless you opt into that in Settings. - Guard rails — warnings before closing with unsaved edits, before an install would replace variants you already have, or before deleting a file that variants still map.
- Family and variant mapping — assign files to weights and styles, all inline in the panel. Files already on the server but not mapped to any family can be adopted into one.
- A CSS variable per family — every family is published as
--efm-family-{slug}, so"Noto Sans Sinhala"is usable asvar(--efm-family-noto-sans-sinhala)in an Etch style record, an ACSS override or any stylesheet. The value carries the family's fallback stack, and the family editor shows the variable ready to copy. This is the intended way to wire a family into Automatic.css: set--heading-font-family: var(--efm-family-inter)in ACSS itself, where the rest of your typography already lives. - Portable import and export — export chosen families as JSON, optionally with the font files bundled in, and preview exactly what an import will add, overwrite and remove before applying it — a genuine dry run that writes nothing until you confirm. Bundled files are validated by their format signature before being written.
- Stylesheet delivery — the generated CSS is cached to a file and enqueued, or printed inline if you prefer one less request. Shows when it was last built, with a regenerate action.
- Blocks other plugins' Google Fonts — an optional privacy setting that dequeues any stylesheet pointing at
fonts.googleapis.comand strips the matching preconnect hints. - Generated CSS preview — see exactly what a family contributes, live as you edit it.
- Instant canvas refresh — the generated stylesheet is reloaded in the builder shell and canvas iframe after every change; no page reload.
- Self-hosted and GDPR friendly — everything is served from your own fonts directory.
- Block editor aware — family names are registered in
theme.jsonso Gutenberg font pickers list them (without duplicate@font-faceoutput).
Multisite storage and WOFF limits
On multisite, each site stores fonts and generated CSS beneath wp-content/fonts/efm-sites/{blog_id}/,
including the main site. Custom storage-directory and URL filters remain base locations; the site namespace
is appended afterwards. Existing mapped fonts are copied without deleting shared originals or overwriting
legacy shared CSS. Unmapped legacy files are not automatically adopted. Migration requires local filesystem
locking and hard-link support for atomic publication; failed copies retry without accepting partial files.
WOFF reconstruction validates table ranges and sizes before allocating output, processes tables sequentially, and feeds the native decompressor in small bounded chunks. Reconstructed fonts larger than 64 MiB are not converted; supply TTF, OTF or WOFF2 instead. This is an output limit, not a cap on total browser memory. Single-site storage paths are unchanged.
Requirements
- WordPress 6.0+
- PHP 7.4+
- Etch 1.6+ (the Controls API is required for the in-builder panel)
- Automatic.css is optional; families are exposed as CSS variables you can feed into it
Installation
- Download the zip from the latest release.
- In WordPress go to Plugins > Add New > Upload Plugin, upload it and activate.
- Open the Etch builder. The Font Manager icon appears in the Settings Bar with Etch's other managers.
Updates
After the first install the plugin updates itself from GitHub releases. New versions show up on the normal Dashboard > Updates screen with the release notes in the details modal, so there is no zip to upload again.
The routine check reads update.json from the raw CDN, which has no API rate limit. GitHub's REST API is only
used as a fallback, because it allows 60 unauthenticated requests an hour per IP address and every site
behind a shared host address draws on the same budget. A failed lookup keeps the last known release rather
than discarding it, and a rate-limited response backs off until the reported reset time.
Lookups are cached for six hours. WordPress itself only asks for update information roughly hourly on the Plugins screen, about every minute on the Updates screen, and twice daily on cron, and both the manual Check for updates link and a forced check bypass the cache, so an active check is always live.
Point the updater at a fork with efm_updater_repo, change the manifest branch with efm_updater_branch,
turn updates off with efm_enable_updates, or change the cache window with efm_release_cache_ttl.
Update packages are only accepted when they come from this repository's own releases, so a tampered manifest cannot redirect WordPress to another download.
On activation, existing data from the older Etch Custom Fonts plugin is imported automatically when present.
Usage
The manager opens from the Font Manager icon in the Settings Bar and has six sections: Font library, Font files, Google Fonts, Settings, Import & export and Trash.
Font library — a specimen grid or row list of your font families with a filter box. Manage opens a family editor for renaming the family, mapping files to weights and styles, typography tokens, delivery and the variable-axis tester. Edits are buffered; Save and Discard appear in the header while there are unsaved changes, and closing the panel with unsaved edits asks first.
Font files — drag and drop .woff2, .woff, .ttf or .otf files, with a running conversion report, and
review everything currently in the fonts folder with type, size, a search box, format chips and a way to adopt a
file already on the server into a family. Multi-select and bulk-delete are available on every table here.
Google Fonts — browse the whole library by category or writing system, sort by popularity, trending, newest
or A to Z, or search it. The writing-system filter is the only reliable way to answer questions like "which families can set
Sinhala". Select several families and install them in one action. Results page in 24 at a time. Families with a
weight axis can be installed as a variable cut: one file per subset instead of one per weight. Pick the
subsets you need first: latin is preselected alongside the family's own script, and other scripts it carries
are offered as toggles. Installing downloads every weight and style for the chosen subsets locally and wires the
family up for you.
Reinstall, on a family you already have, opens on exactly what is installed — the same subsets, the same weights, static or variable — so pressing it with nothing changed does nothing. Change the selection and it asks first, naming which variants would be dropped, because installing replaces a family's variant list rather than merging into it.
Subsets matter. A family such as Noto Sans Sinhala carries
sinhala,latin-extandlatin. Installing latin alone gives you a font with no Sinhala glyphs, and the browser silently falls back to a system font.
Family editor → Delivery — set font-display, opt a family into preloading, give it a fallback stack, an
Apply to selector list, and optionally a metric-matched local fallback face so text does not shift when the
real font arrives.
Family editor → Typography tokens — publish a family as the site's heading or body font. Each token belongs to one family; assigning it to a new family unassigns the old one.
Import & export — download the whole configuration as JSON and load it on another site, in replace or merge
mode, with a genuine dry run (preview: true) that reports what would change before anything is written. Any
font file a family references but that is missing from the destination is listed after the import.
Trash — a family moved here keeps its files; restore undoes it completely, and deleting permanently removes only the record. Deleted files can be recovered separately from Import & export while they are still on disk.
Settings — choose whether the generated stylesheet is enqueued as a file or printed inline, regenerate it on demand, optionally block Google Fonts loaded by other themes and plugins, delete a converted original after it is converted, and choose whether uninstalling the plugin also deletes the font files and stylesheet it created (off by default — removing the plugin never removes your fonts unless you ask it to).
Read the full README on GitHub →
Releases
| Tag | Published | Asset | Downloads |
|---|---|---|---|
| v1.0.2 | Sep 6, 2026 | etch-font-manager.zip | 5 |
| v1.0.1 | Sep 4, 2026 | etch-font-manager.zip | 4 |
| v1.0.0 | Sep 3, 2026 | etch-font-manager.zip | 5 |
| v0.36.4 | Sep 3, 2026 | etch-font-manager.zip | 5 |
| v0.36.3 | Sep 3, 2026 | etch-font-manager.zip | 3 |
| v0.36.2 | Sep 3, 2026 | etch-font-manager.zip | 5 |
| v0.36.1 | Sep 2, 2026 | etch-font-manager.zip | 4 |
| v0.36.0 | Sep 2, 2026 | etch-font-manager.zip | 4 |
| v0.35.0 | Sep 1, 2026 | etch-font-manager.zip | 4 |
| v0.34.1 | Sep 1, 2026 | etch-font-manager.zip | 3 |
| v0.34.0 | Sep 1, 2026 | etch-font-manager.zip | 4 |
| v0.33.0 | Aug 30, 2026 | etch-font-manager.zip | 4 |
| v0.32.0 | Aug 24, 2026 | etch-font-manager.zip | 4 |
| v0.31.0 | Aug 23, 2026 | etch-font-manager.zip | 6 |
| v0.30.0 | Aug 22, 2026 | etch-font-manager.zip | 6 |
| v0.29.0 | Aug 22, 2026 | etch-font-manager.zip | 3 |
| v0.28.0 | Aug 17, 2026 | etch-font-manager.zip | 4 |
| v0.27.0 | Aug 16, 2026 | etch-font-manager.zip | 4 |
| v0.26.0 | Aug 16, 2026 | etch-font-manager.zip | 3 |
| v0.25.0 | Aug 15, 2026 | etch-font-manager.zip | 2 |
Active-site estimate ≈10 comes from the v0.31.0 cohort. Method.