DEV Community

Vladimir Grigoryan
Vladimir Grigoryan

Posted on Fully Autonomous

Running Kokoro in WordPress: generate in the admin tab, serve a saved file

A browser TTS demo usually ends when the audio starts playing. For a WordPress article, that's only part of the job. The recording also needs to survive the tab closing, stay attached to the right post, and keep working for readers on phones.

The approach I use is to generate the audio in the site owner's admin browser and save a file in WordPress. Readers then play that file. They never need to load the speech model.

The flow looks like this:

Saved post
  -> text prepared for speech
  -> Kokoro in the admin browser
  -> audio samples
  -> encode an audio file
  -> upload to WordPress
  -> Media Library attachment
  -> article player
Enter fullscreen mode Exit fullscreen mode

Kokoro produces audio; MP3 encoding is a separate step. The kokoro-js examples save WAV files. If your publishing workflow needs MP3, include an encoder rather than changing the filename extension.

There are three things I'd decide before wiring up the player.

First, what exactly gets read? A post can contain headings, captions, code, tables, and embeds. Stripping all the HTML won't tell you whether a table makes sense when spoken. Show the prepared text or a report of skipped sections, then listen to a representative post before recording an archive. Names and abbreviations deserve a check too.

Second, where does the work happen? Keep inference in the admin screen. WordPress already handles the post, the user's permissions, and media storage. It doesn't need to run the speech model in this design. But this also means recording depends on the owner's machine and the browser tab staying open. It isn't an overnight server job.

The kokoro-js README documents WebAssembly and WebGPU backends and recommends fp32 for WebGPU. Test the path you actually ship on the hardware you expect people to use. A short sample can tell you whether generation works; an estimate extrapolated from it isn't a measured recording time for a long article.

Third, what happens after an edit? An attachment ID alone doesn't tell you whether the recording matches the current post. I'd keep a record shaped something like this, with illustrative values:

{
  "post_id": 123,
  "attachment_id": 456,
  "spoken_text_hash": "hash-of-the-prepared-text",
  "voice": "af_heart",
  "backend": "webgpu",
  "dtype": "fp32"
}
Enter fullscreen mode Exit fullscreen mode

Hash the text you actually send to the model. When that text changes, mark the recording as out of date. Keep the previous audio available until its replacement has been uploaded successfully. A failed upload shouldn't remove the version readers can already play.

WordPress's Media REST API supports creating an attachment and associating it with a post. An admin integration also needs authenticated requests and permission checks. Once the file is stored, the public page can use an ordinary audio player. Keep the inference runtime out of that page's bundle.

There's also a privacy detail worth spelling out: local speech generation means the text can be processed without sending it to a TTS provider. Your WordPress host still stores the post, receives the recording, and serves it to readers. The initial model download needs a connection, and a browser cache can be cleared.

Before calling the workflow finished, I'd test a short post, a post with a table or code block, an interrupted recording, a failed upload, and an edit after recording. Then open the published article on a different device. That checks the handoff from generation to playback, which a browser demo by itself doesn't cover.

References: kokoro-js usage and backends, WordPress Media REST API.

I used AI assistance to draft and edit this article.

Top comments (0)