Why Add Voice AI to Your WordPress Site?
If you’ve ever wanted to give your blog posts, product pages, or tutorials a human‑like voice, you’re not alone. Text‑to‑speech (TTS) and voice cloning have moved from experimental labs into everyday tools that boost accessibility, increase dwell time, and even improve SEO (Google loves rich media).
WordPress makes it easy to add any kind of content, but hooking up a high‑quality TTS engine still requires a bit of plumbing. In this post we’ll walk through a practical, developer‑friendly way to integrate ElevenLabs (the service that’s raising the bar for natural‑sounding speech) directly into WordPress.
Quick note: The examples below use the public API key you get after signing up at ElevenLabs. Feel free to replace it with your own key when you go live.
Overview of the Workflow
- Capture the text you want spoken (post content, custom field, or user input).
- Call the ElevenLabs API to generate an MP3 (or WAV) file.
- Store the audio in the WordPress uploads folder.
-
Render an HTML5
<audio>player or embed the file in a Gutenberg block.
We’ll implement this as a simple shortcode ([tts]) that you can drop anywhere in a post or page.
Getting an ElevenLabs API Key
- Sign up at the official link: https://try.elevenlabs.io/kr07zfuqn1bp.
- Navigate to Dashboard → API Keys.
- Copy the generated key – you’ll need it in your
wp-config.phpor a site‑specific plugin.
Setting Up a Minimal Plugin
Create a folder called wp-tts-elevenlabs inside wp-content/plugins and add a file named wp-tts-elevenlabs.php:
<?php
/**
* Plugin Name: ElevenLabs TTS for WordPress
* Description: Turn any text into natural‑sounding speech using ElevenLabs.
* Version: 1.0
* Author: Your Name
*/
if ( ! defined( 'ABSPATH' ) ) exit; // Prevent direct access
// Load the API key from wp-config.php (add define('ELEVENLABS_API_KEY', 'your_key'); there)
function eleventlabs_get_api_key() {
return defined('ELEVENLABS_API_KEY') ? ELEVENLABS_API_KEY : '';
}
/**
* Shortcode: [tts voice="emma"]Your text here[/tts]
*/
function eleventlabs_tts_shortcode( $atts, $content = '' ) {
$atts = shortcode_atts( [
'voice' => 'Rachel', // default voice from ElevenLabs
'format'=> 'mp3',
], $atts, 'tts' );
// Sanitize input
$text = trim( wp_strip_all_tags( $content ) );
$voice = sanitize_text_field( $atts['voice'] );
$format = sanitize_key( $atts['format'] );
if ( empty( $text ) ) return '';
// Build a unique filename based on hash
$hash = md5( $voice . $text );
$upload = wp_upload_dir();
$file_path = trailingslashit( $upload['basedir'] ) . "tts-{$hash}.{$format}";
$file_url = trailingslashit( $upload['baseurl'] ) . "tts-{$hash}.{$format}";
// If the file already exists, skip the API call
if ( ! file_exists( $file_path ) ) {
$audio = eleventlabs_generate_audio( $text, $voice, $format );
if ( is_wp_error( $audio ) ) {
return '<!-- TTS error: ' . esc_html( $audio->get_error_message() ) . ' -->';
}
// Save the binary data to the uploads folder
file_put_contents( $file_path, $audio );
}
// Return an HTML5 audio player
return '<audio controls src="' . esc_url( $file_url ) . '"></audio>';
}
add_shortcode( 'tts', 'eleventlabs_tts_shortcode' );
/**
* Calls ElevenLabs API and returns raw audio bytes.
*/
function eleventlabs_generate_audio( $text, $voice, $format = 'mp3' ) {
$api_key = eleventlabs_get_api_key();
if ( ! $api_key ) {
return new WP_Error( 'no_key', 'ElevenLabs API key not set.' );
}
$endpoint = "https://api.elevenlabs.io/v1/text-to-speech/{$voice}";
$args = [
'headers' => [
'Accept' => "audio/{$format}",
'Content-Type' => 'application/json',
'xi-api-key' => $api_key,
],
'body' => wp_json_encode( [
'text' => $text,
'model_id' => 'eleven_monolingual_v1',
'voice_settings' => [
'stability' => 0.75,
'similarity_boost' => 0.85,
],
] ),
'timeout' => 30,
];
$response = wp_remote_post( $endpoint, $args );
if ( is_wp_error( $response ) ) {
return $response;
}
$code = wp_remote_retrieve_response_code( $response );
if ( $code !== 200 ) {
return new WP_Error( 'api_error', "ElevenLabs returned {$code}" );
}
return wp_remote_retrieve_body( $response );
}
What the Plugin Does
-
Shortcode –
[tts voice="Emma"]Hello world![/tts]inserts an audio player. -
Caching – Generates a deterministic filename (
tts-{hash}.mp3). If the same text/voice combo is requested again, we serve the cached file, saving API credits. - Error handling – If the API key is missing or the request fails, the shortcode silently outputs an HTML comment (so the page still renders).
Testing the Integration with curl
Before you rely on the PHP wrapper, it’s handy to verify the raw API works. Replace YOUR_API_KEY and VOICE_ID (e.g., Rachel) with your values:
curl -X POST "https://api.elevenlabs.io/v1/text-to-speech/Rachel" \
-H "Accept: audio/mp3" \
-H "Content-Type: application/json" \
-H "xi-api-key: YOUR_API_KEY" \
-d '{
"text": "Welcome to my WordPress site!",
"model_id": "eleven_monolingual_v1",
"voice_settings": {
"stability": 0.7,
"similarity_boost": 0.9
}
}' --output welcome.mp3
You should end up with a welcome.mp3 file that sounds like a real person. If you want to experiment with voice cloning, ElevenLabs lets you upload a short sample (≈10‑30 seconds) and then reference the new voice ID in the same endpoint.
Adding a Gutenberg Block (Optional)
If you prefer a UI over a shortcode, you can register a simple block that re‑uses the same PHP function:
// src/block.js
import { registerBlockType } from '@wordpress/blocks';
import { TextControl, SelectControl } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
registerBlockType('elevenlabs/tts', {
title: __('ElevenLabs TTS', 'elevenlabs-tts'),
icon: 'format-audio',
category: 'embed',
attributes: {
text: { type: 'string' },
voice: { type: 'string', default: 'Rachel' },
},
edit: ({ attributes, setAttributes }) => {
const [preview, setPreview] = useState('');
const generate = async () => {
const resp = await fetch('/wp-json/elevenlabs/v1/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(attributes),
});
const data = await resp.json();
if (data.url) setPreview(data.url);
};
return (
<>
<TextControl
label={__('Text to speak', 'elevenlabs-tts')}
value={attributes.text}
onChange={(t) => setAttributes({ text: t })}
/>
<SelectControl
label={__('Voice', 'elevenlabs-tts')}
value={attributes.voice}
options={[
{ label: 'Rachel', value: 'Rachel' },
{ label: 'Emma', value: 'Emma' },
// Add more voices as needed
]}
onChange={(v) => setAttributes({ voice: v })}
/>
<button onClick={generate}>{__('Generate Audio', 'elevenlabs-tts')}</button>
{preview && <audio controls src={preview} />}
</>
);
},
save: () => null, // rendered server‑side via shortcode
});
You’d expose a tiny REST endpoint (/wp-json/elevenlabs/v1/generate) that proxies the same PHP logic. This is optional but gives non‑technical editors a button‑click experience.
Best Practices & Gotchas
| Concern | Recommendation |
|---|---|
| API quota | Cache generated files aggressively. Use the hash‑based filename strategy shown above. |
| Voice cloning latency | Uploading a new voice can take a few seconds. Do the cloning step during site setup, not on every page view. |
| File size | MP3 at 64 kbps is usually enough for spoken content. Adjust format or use audio/mpeg with lower bitrate if you need to save bandwidth. |
| Security | Never expose your API key to the front‑end. All calls must go through server‑side code (PHP or a custom endpoint). |
| Accessibility | Provide a fallback transcript (<noscript> or hidden <p>), as screen readers already read the text. The audio is a complement, not a replacement. |
Putting It All Together
- Install the plugin (or drop the code into a site‑specific plugin).
-
Add
define('ELEVENLABS_API_KEY', 'YOUR_KEY');towp-config.php. - Create a post and use the shortcode:
Here’s a quick demo of my new feature:
[tts voice="Emma"]Welcome to the future of WordPress content![/tts]
- Publish and listen to the generated audio right in the browser.
That’s it—no external services, no heavy JavaScript SDKs, just a clean PHP wrapper around a world‑class TTS engine.
Ready to Give Your Site a Voice?
ElevenLabs makes it surprisingly simple to turn any piece of text into a lifelike narration, and with the code above you can start experimenting in minutes. Grab your free API key at https://try.elevenlabs.io/kr07zfuqn1bp, install the plugin, and watch your WordPress content come alive. Happy coding!
Top comments (0)