Install
This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/donohoe/clear-embed/archive/refs/heads/main.zipA WordPress plugin that replaces third-party embeds with lightweight, privacy-respecting versions rendered from local metadata and templates. ClearEmbed caches content locally and provides click-to-activate embed loading for improved privacy and performance.
⚠️ Development Status
ClearEmbed is still in active development. While the core functionality is working, you may encounter bugs or incomplete features. Use with caution in production environments and report any issues you find.
Features
- Privacy-First: Click-to-load embeds reduce tracking and improve privacy
- Performance: Lightweight local templates instead of heavy third-party scripts
- Offline-Ready: Stores embed data locally for better reliability
- Image Optimization: Automatically creates mobile-optimized versions of images
- Profile Image Caching: Downloads and caches creator/channel avatars locally
- Deleted Content Tracking: Monitors embed availability and preserves deleted content
- Extensible: Service-based architecture for easy addition of new platforms
- Cache-Friendly: All embed data stored on filesystem, not database
- Admin Interface: Settings panel with service management and maintenance tools
Supported Services
- ✅ YouTube - Videos with thumbnails, channel avatars, and metadata
- ✅ Twitter/X - Tweets with OpenGraph cards, media detection, and profile images
- ✅ Spotify - Tracks, albums, episodes, shows with artwork and custom audio player
- ✅ TikTok - Videos with thumbnails and creator avatars
- ✅ Bluesky - Posts with media grids, video support, and profile images
- 🔲 SoundCloud
- 🔲 SnapChat
- 🔲 Vimeo
Installation
- Upload the plugin files to
/wp-content/plugins/embeds/ - Activate the plugin through the WordPress admin
- Configure settings at Settings > Embeds
- Enable desired services in the settings panel
Directory Structure
/wp-content/embeds/
├── youtube/
│ └── {video_id}/
│ ├── data.json
│ ├── image.jpg
│ ├── image-mobile.jpg
│ └── avatar.jpg
├── twitter/
│ └── {tweet_id}/
│ ├── data.json
│ ├── card.jpg
│ ├── card-mobile.jpg
│ └── avatar.jpg
├── spotify/
│ └── {track_id}/
│ ├── data.json
│ ├── image.jpg
│ ├── image-mobile.jpg
│ └── avatar.jpg
├── tiktok/
│ └── {video_id}/
│ ├── data.json
│ ├── image.jpg
│ ├── image-mobile.jpg
│ └── avatar.jpg
├── bluesky/
│ └── {post_id}/
│ ├── data.json
│ ├── image-1.jpg
│ ├── image-1-mobile.jpg
│ ├── card.jpg
│ ├── card-mobile.jpg
│ └── avatar.jpg
└── .htaccess
Service Features
YouTube
- Data Source: oEmbed API + channel page scraping
- Content: Video metadata, thumbnails, channel information
- Images: Video thumbnails (multiple quality fallbacks), channel avatars
- Features: Click-to-play with iframe loading, channel links
Twitter/X
- Data Source: oEmbed API + HTML parsing
- Content: Tweet text, author info, OpenGraph cards
- Images: Card images, profile avatars, media detection
- Features: Card previews, media indicators, engagement metrics
Spotify
- Data Source: oEmbed API + NextJS data extraction
- Content: Track/episode metadata, artwork, preview audio
- Images: Album/show artwork, artist avatars (tracks only)
- Features: Custom audio player, dynamic theming, duration display
TikTok
- Data Source: oEmbed API + page scraping
- Content: Video metadata, creator info, engagement stats
- Images: Video thumbnails, creator avatars
- Features: Engagement metrics, click-to-play interface
Bluesky
- Data Source: AT Protocol API
- Content: Post text, author info, media, external links
- Images: Post images (1-4 grid), card images, profile avatars
- Features: Media grids, video support, external link cards
Privacy & Performance Features
Click-to-Activate
All embeds load as static previews initially, only loading third-party content when clicked by the user.
Local Image Caching
- Thumbnails: Cached locally with mobile-optimized versions
- Profile Images: Creator/channel avatars cached for all services
- Responsive: Automatic mobile versions for bandwidth optimization
- Privacy: No external image requests on page load
Deleted Content Tracking
- Availability Monitoring: Periodic checks for deleted/private content
- Lazy Checking: Checks performed only when content is accessed
- Preservation: Option to preserve deleted embed data
- Admin Tools: Bulk maintenance and selective deletion
Admin Interface
Settings Panel (Settings > ClearEmbed)
- Service Management: Enable/disable individual services
- Discovered Services: Auto-detection of available service handlers
- Maintenance Tools: Clear embed data with preservation options
- Statistics: Embed counts and storage usage
Service Discovery
The plugin automatically discovers service handlers in the /services/ directory and provides admin controls for enabling/disabling them.
Extensibility
Adding Custom Services
- Create service directory:
/services/my-service/ - Add handler class:
/services/my-service/handler.php - Add template:
/services/my-service/template.php
<?php
class ClearEmbed_MyService_Handler extends ClearEmbed_Service_Handler {
protected $service_name = 'my-service';
public function can_handle($url) {
return strpos($url, 'example.com') !== false;
}
public function extract_embed_id($url) {
// Extract unique ID from URL
}
public function fetch_embed_data($url, $embed_id) {
// Fetch and return embed data array
}
public function get_template_data($embed_data) {
// Transform data for template use
}
public function check_embed_availability($url, $embed_id) {
// Check if content still exists
}
public function get_supported_patterns() {
return array('example.com/*');
}
}
Template Structure
Templates receive processed data and should handle responsive display:
<?php if (!defined('ABSPATH')) exit; ?>
<div class="clearembed-myservice" data-id="<?php echo esc_attr($id); ?>">
<!-- Static preview content -->
<div class="clearembed-myservice-placeholder" onclick="loadEmbed()">
<!-- Preview with local images -->
</div>
<!-- Hidden iframe for click-to-load -->
<iframe data-src="<?php echo esc_url($embed_url); ?>" style="display:none;"></iframe>
</div>
WordPress Filters
ClearEmbed provides extensive filter hooks for customization:
Core Processing Filters
clearembed_processable_url
Parameters: $should_process, $url
Description: Control whether a URL should be processed by ClearEmbed
add_filter('clearembed_processable_url', function($should_process, $url) {
// Skip processing for specific domains
if (strpos($url, 'internal.example.com') !== false) {
return false;
}
return $should_process;
}, 10, 2);
clearembed_embed_html
Parameters: $html, $service, $embed_data
Description: Modify final embed HTML output
add_filter('clearembed_embed_html', function($html, $service, $embed_data) {
// Add custom wrapper for YouTube embeds
if ($service === 'youtube') {
return '<div class="custom-youtube-wrapper">' . $html . '</div>';
}
return $html;
}, 10, 3);
clearembed_fallback_content
Parameters: $fallback, $url, $service
Description: Provide custom fallback content when embed processing fails
add_filter('clearembed_fallback_content', function($fallback, $url, $service) {
return '<p>Content from ' . $service . ' is temporarily unavailable.</p>';
}, 10, 3);
Service Management Filters
clearembed_enabled_services
Parameters: $enabled_services
Description: Programmatically control which services are enabled
add_filter('clearembed_enabled_services', function($services) {
// Disable TikTok on production
if (WP_ENV === 'production') {
$services = array_diff($services, ['tiktok']);
}
return $services;
});
clearembed_supported_services
Parameters: $services
Description: Filter the list of supported services
Data Processing Filters
clearembed_embed_data
Parameters: $embed_data, $service, $url
Description: Modify embed data before storage
add_filter('clearembed_embed_data', function($data, $service, $url) {
// Add custom metadata
$data['processed_at'] = current_time('c');
$data['source_domain'] = parse_url($url, PHP_URL_HOST);
return $data;
}, 10, 3);
clearembed_template_data
Parameters: $template_data, $embed_data, $service
Description: Modify data passed to templates
add_filter('clearembed_template_data', function($template_data, $embed_data, $service) {
// Add custom CSS classes
$template_data['custom_class'] = 'my-theme-embed';
return $template_data;
}, 10, 3);
Image Processing Filters
clearembed_skip_image_download
Parameters: $skip, $url, $service, $image_type
Description: Skip image downloads conditionally
add_filter('clearembed_skip_image_download', function($skip, $url, $service, $type) {
// Skip avatar downloads for YouTube
if ($service === 'youtube' && $type === 'avatar') {
return true;
}
return $skip;
}, 10, 4);
clearembed_image_quality
Parameters: $quality, $service, $image_type
Description: Control JPEG compression quality
add_filter('clearembed_image_quality', function($quality, $service, $type) {
// Higher quality for thumbnails
if ($type === 'thumbnail') {
return 95;
}
return $quality;
}, 10, 3);
API Request Filters
clearembed_api_request_args
Parameters: $args, $service, $request_type
Description: Modify API request arguments
add_filter('clearembed_api_request_args', function($args, $service, $type) {
// Add custom headers for Spotify
if ($service === 'spotify') {
$args['headers']['X-Custom-Header'] = 'MyApp/1.0';
}
return $args;
}, 10, 3);
Content Sanitization Filters
clearembed_sanitize_content
Parameters: $content, $content_type, $service
Description: Sanitize content before display
add_filter('clearembed_sanitize_content', function($content, $type, $service) {
// Custom sanitization for Twitter text
if ($service === 'twitter' && $type === 'text') {
return wp_kses_post($content);
}
return $content;
}, 10, 3);
Template System Filters
clearembed_template_path
Parameters: $template_path, $service
Description: Override template file paths
add_filter('clearembed_template_path', function($path, $service) {
// Use theme template if available
$theme_template = get_template_directory() . '/clearembed/' . $service . '.php';
if (file_exists($theme_template)) {
return $theme_template;
}
return $path;
}, 10, 2);
clearembed_css_classes
Parameters: $classes, $service, $context
Description: Modify CSS classes in templates
add_filter('clearembed_css_classes', function($classes, $service, $context) {
// Add dark mode class
if (get_theme_mod('dark_mode_enabled')) {
$classes[] = 'dark-mode';
}
return $classes;
}, 10, 3);
Service-Specific Filters
clearembed_embed_url_params
Parameters: $params, $service, $embed_id
Description: Modify iframe embed URL parameters
add_filter('clearembed_embed_url_params', function($params, $service, $id) {
// Disable YouTube related videos
if ($service === 'youtube') {
$params['rel'] = '0';
$params['modestbranding'] = '1';
}
return $params;
}, 10, 3);
Configuration Filters
clearembed_availability_check_days
Parameters: $days
Description: Control how often embed availability is checked
add_filter('clearembed_availability_check_days', function($days) {
return 14; // Check every 2 weeks instead of 7 days
});
Usage Examples
Custom YouTube Embed Parameters
// Disable related videos and enable modest branding
add_filter('clearembed_embed_url_params', function($params, $service, $id) {
if ($service === 'youtube') {
$params['rel'] = '0';
$params['modestbranding'] = '1';
$params['color'] = 'white';
}
return $params;
}, 10, 3);
Skip Processing for Internal URLs
// Don't process embeds from internal staging sites
add_filter('clearembed_processable_url', function($should_process, $url) {
$internal_domains = ['staging.example.com', 'dev.example.com'];
$domain = parse_url($url, PHP_URL_HOST);
if (in_array($domain, $internal_domains)) {
return false;
}
return $should_process;
}, 10, 2);
Custom Error Handling
// Provide branded fallback content
add_filter('clearembed_fallback_content', function($fallback, $url, $service) {
$service_name = ucfirst($service);
return sprintf(
'<div class="embed-error"><p>%s content is currently unavailable. <a href="%s" target="_blank">View on %s</a></p></div>',
$service_name,
esc_url($url),
$service_name
);
}, 10, 3);
Available Hooks
- Service Registration: Automatic discovery from
/services/directory - Template Override: Place custom templates in theme directory
- Data Processing: Filter embed data before storage/display
- Image Processing: Customize image optimization settings
Requirements
- WordPress 5.0+
- PHP 7.4+
- Writable
/wp-content/embeds/directory - GD extension (for image processing)
- cURL/WordPress HTTP API (for remote requests)
Privacy Forward
- No Third-Party Requests: Content loads only when user explicitly clicks
- Local Storage: All data cached locally, no external dependencies
- GDPR Friendly: Reduces tracking and data collection from embed providers
- User Control: Click-to-activate gives users choice over loading external content
Performance Benefits
- Reduced Page Weight: Local templates much lighter than third-party widgets
- Faster Loading: No blocking requests to external services
- Mobile Optimized: Responsive images reduce bandwidth usage
- Caching: Filesystem storage eliminates database overhead
License
GPL v2 or later