WordPress Plugin: Dynamic Favicons for Live Content and Campaigns
Automate WordPress favicons for live streams, campaigns and tickers—plugin tutorial with caching, manifest and PWA best practices for 2026.
Hook: Stop wasting hours generating icons — automate dynamic favicons for campaigns, live content and stock tickers
If you manage WordPress sites with live streams, flash sales, or market feeds, you know the pain: manually building dozens of icon sizes, deploying them, and hoping browsers and PWAs pick up updates. In 2026, brands are using favicons as micro-moment signals—LIVE badges, campaign colors and even dynamic cashtags—so automation and correct caching matter. This tutorial shows a production-ready WordPress plugin pattern that updates favicons dynamically from posts (live, promo, ticker), plus caching, manifest and PWA best practices you can drop into CI/CD.
What you’ll get
- Plugin blueprint that generates favicon packs from a post (PHP + JS)
- Examples: live stream “LIVE” badge, campaign color overlays, stock ticker overlay
- Cache-control, ETag and service-worker recommendations for correct updates
- manifest.json and PWA integration tips for 2026 browser behavior
- CI/CD & WP-CLI tasks to automate asset generation
Why dynamic favicons matter in 2026
Favicons are no longer just decoration. Brands use them for micro-interactions—live badges during streams, campaign flags during ads, or cashtag overlays for finance coverage. Recent social features and campaigns in late 2025 and early 2026 highlighted how bite-sized visual signals influence installs and engagement. On the web, a correctly timed favicon change can increase attention and clicks from tabs, bookmarks and PWA shortcuts.
"Microbrand cues like a LIVE favicon can raise immediate CTR on an open tab—use them sparingly and automate reliably."
Strategy overview
- Source icon: a high-resolution master (1024–4096 px, PNG/AVIF/WEBP).
- Generator: server-side image resizing (WP_Image_Editor / Imagick). For field-ready workflows and on-location builds, references on compact streaming rigs and capture kits can be handy when producing master assets.
- Dispatcher: plugin endpoint (REST) that switches which favicon files are linked in
<head>based on post state — pair this with realtime triggers or messaging systems (see WebRTC/Firebase patterns such as run realtime workrooms without Meta for inspiration). - Caching: fingerprint files for long cache TTL; use short TTL or versioned URLs for manifest.json / HTML to signal updates.
- PWA: include maskable icons and correct manifest icon entries; control manifest caching with versioning.
Plugin: core concepts (quick)
We’ll build a plugin that:
- Creates a favicon pack when a post gets a campaign meta (e.g.,
campaign_type). - Stores generated files in
wp-content/uploads/favicons/{post_id}/. - Exposes REST route to trigger regeneration and to attach live-preview tokens for admin previewing.
- Injects correct
<link rel="icon">and manifest link in the front-endhead.
Plugin skeleton (PHP)
<?php
/**
* Plugin Name: Dynamic Favicons for Live Content
* Description: Generate and switch favicons per post/campaign. Example for devs and ops.
* Version: 1.0.0
* Author: Favicon.Live (example)
*/
if ( ! defined( 'ABSPATH' ) ) exit;
class DL_Dynamic_Favicons {
public function __construct() {
add_action( 'save_post', [ $this, 'on_save_post' ], 20, 3 );
add_action( 'wp_head', [ $this, 'print_favicon_links' ] );
add_action( 'rest_api_init', [ $this, 'register_routes' ] );
}
public function on_save_post( $post_ID, $post, $update ) {
$campaign = get_post_meta( $post_ID, 'campaign_type', true );
if ( $campaign ) {
$this->generate_pack( $post_ID, $campaign );
}
}
protected function generate_pack( $post_id, $campaign ) {
// 1) Choose master image (post thumbnail or default)
$src_id = get_post_thumbnail_id( $post_id ) ?: get_option( 'site_icon' );
$src = wp_get_original_image_path( $src_id );
if ( ! $src || ! file_exists( $src ) ) return false;
// 2) Create output dir
$upload = wp_upload_dir();
$dest_dir = trailingslashit( $upload['basedir'] ) . "favicons/{$post_id}/";
wp_mkdir_p( $dest_dir );
// 3) Use WP_Image_Editor to create sizes
$sizes = [ 16, 32, 48, 64, 192, 512 ];
$editor = wp_get_image_editor( $src );
if ( is_wp_error( $editor ) ) return false;
foreach ( $sizes as $s ) {
$editor->resize( $s, $s, true );
$out = $dest_dir . "favicon-{$s}.png";
$editor->save( $out );
$editor->resize( $editor->get_size()['width'], $editor->get_size()['height'], false );
}
// 4) Add campaign overlay (simple text overlay shown in examples below)
$this->apply_overlay( $dest_dir, $campaign );
// 5) return manifest-ready object
return true;
}
protected function apply_overlay( $dest_dir, $campaign ) {
// Example: add a red "LIVE" badge at 512 size and regenerate lower sizes from it
$src = $dest_dir . 'favicon-512.png';
if ( ! file_exists( $src ) ) return;
$editor = wp_get_image_editor( $src );
if ( is_wp_error( $editor ) ) return;
// Draw simple overlay with Imagick if available. This is illustrative.
if ( class_exists( 'Imagick' ) ) {
$i = new Imagick( $src );
$draw = new ImagickDraw();
$draw->setFillColor( 'rgba(255,0,0,0.9)' );
$draw->rectangle( 0, 0, 120, 40 );
$i->drawImage( $draw );
$i->setImageFormat( 'png32' );
$i->writeImage( $dest_dir . 'favicon-512.png' );
}
// Recreate smaller sizes from modified 512
$sizes = [ 192, 64, 48, 32, 16 ];
foreach ( $sizes as $s ) {
$editor = wp_get_image_editor( $dest_dir . 'favicon-512.png' );
$editor->resize( $s, $s, true );
$editor->save( $dest_dir . "favicon-{$s}.png" );
}
}
public function print_favicon_links() {
global $post;
if ( ! $post ) return;
$upload = wp_upload_dir();
$dir = trailingslashit( $upload['baseurl'] ) . "favicons/{$post->ID}/";
// Use versioning (filemtime) to bust caches
$v = '';
$f512 = $upload['basedir'] . "/favicons/{$post->ID}/favicon-512.png";
if ( file_exists( $f512 ) ) $v = '?v=' . filemtime( $f512 );
echo "\n\n";
echo "\n";
echo "\n";
echo "\n";
}
public function register_routes() {
register_rest_route( 'dl-favicons/v1', '/regen/(?P\d+)', [
'methods' => 'POST',
'callback' => [ $this, 'rest_regen' ],
'permission_callback' => function() { return current_user_can( 'edit_posts' ); }
] );
}
public function rest_regen( $request ) {
$id = (int) $request['id'];
$campaign = get_post_meta( $id, 'campaign_type', true );
$this->generate_pack( $id, $campaign );
return rest_ensure_response( [ 'ok' => true ] );
}
}
new DL_Dynamic_Favicons();
?>
Client-side live preview (admin)
For instant feedback, swap the favicon link tag in the admin preview using JS—no reload needed:
fetch('/wp-json/dl-favicons/v1/regen/123', { method: 'POST', credentials: 'include' })
.then(() => {
const link = document.querySelector('link[rel~="icon"]');
link.href = '/wp-content/uploads/favicons/123/favicon-32.png?v=' + Date.now();
});
manifest.json and PWA best practices (2026)
Browsers in 2026 aggressively cache static assets. The manifest is fetched and cached by Chrome, Safari and other engines—so when you change icons, you must force the browser to re-fetch either by:
- Changing the manifest URL (add a version query string:
manifest.json?v=20260117), or - Including a new icon filename (fingerprinted) in the manifest
Example manifest contents you should generate into the per-post folder:
{
"name": "Example Site - Campaign A",
"short_name": "Site",
"start_url": "/?source=web_app",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#ff0000",
"icons": [
{ "src": "/wp-content/uploads/favicons/123/favicon-192.png?v=1610000", "sizes": "192x192", "type": "image/png", "purpose": "any maskable" },
{ "src": "/wp-content/uploads/favicons/123/favicon-512.png?v=1610000", "sizes": "512x512", "type": "image/png", "purpose": "any maskable" }
]
}
Important manifest notes
- Maskable icons allow adaptive shapes on Android/Chromium-based platforms—include maskable entries.
- Version the manifest when changing icons; many browsers cache manifest.json for hours to days.
- Start_url should include a query param for tracking or to force state if you use different icons per campaign.
Caching and HTTP headers
Correct caching avoids stale icons in tabs. Two patterns work well:
- Fingerprint files, long TTL: If the file name changes when content changes (e.g., favicon-512.ab12cd.png), set Cache-Control: public, max-age=31536000, immutable. CDNs and browsers will cache aggressively.
- Versioned querystrings for single filename: If you keep filenames stable, append a version param (e.g., ?v=1674012345) and set a medium TTL. Prefer fingerprinting for CDNs.
Recommended server headers (nginx example for fingerprinted favicons):
location ~* /wp-content/uploads/favicons/.*\.[0-9a-f]{8}\.png$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
location ~* /wp-content/uploads/favicons/ {
add_header Cache-Control "public, max-age=3600"; # shorter for non-fingerprinted
}
For dynamic REST endpoints that trigger regeneration, return Cache-Control: no-cache and use ETag where possible to allow revalidation. Example PHP header:
header('Cache-Control: no-cache, must-revalidate');
header('ETag: "' . md5($body) . '"');
Service worker strategy
If you use a service worker, it can hold older files in cache. Use a clear strategy:
- Cache-first for static app shell (fingerprinted assets).
- Stale-while-revalidate for icons so the user gets fast response while worker fetches updated image.
- When a new favicon is generated, send a message to clients (postMessage) to update the DOM link href — patterns for realtime messaging and client updates are described in guides on running realtime apps (run realtime workrooms without Meta).
// In service-worker.js - simplified
self.addEventListener('message', (e) => {
if (e.data && e.data.type === 'FAVICON_UPDATED') {
// optionally skip waiting and trigger update
self.clients.matchAll().then(clients => {
clients.forEach(c => c.postMessage({ type: 'REFRESH_FAVICON', url: e.data.url }));
});
}
});
// In client page
navigator.serviceWorker.addEventListener('message', (e) => {
if (e.data.type === 'REFRESH_FAVICON') {
const link = document.querySelector('link[rel~="icon"]');
link.href = e.data.url + '?v=' + Date.now();
}
});
CI/CD and automation
Integrate favicon generation into your pipeline so deploys and scheduled campaigns don’t rely on manual clicks. Options:
- Use WP-CLI command to generate packs during deploy. Example:
wp dl-favicons regen 123— build this into your deploy tasks similarly to other content pipelines (production playbooks). - Run a Node-based asset builder (Sharp/Imagemagick) in CI to create full packs, upload to S3/CDN and update post meta with new URLs.
- Use GitHub Actions/Bitbucket Pipelines to call the REST trigger after uploading new master images.
WP-CLI example
// add a simple CLI command that calls the plugin's generation
if ( defined( 'WP_CLI' ) && WP_CLI ) {
WP_CLI::add_command( 'dl-favicons', function( $args ) {
$id = intval( $args[0] );
$d = new DL_Dynamic_Favicons();
$d->generate_pack( $id, get_post_meta( $id, 'campaign_type', true ) );
WP_CLI::success( "Regenerated favicons for {$id}" );
} );
}
Case studies & patterns
1) Live stream site
Use a post meta flag is_live. When set true, generate a red 'LIVE' overlay and call /regen endpoint. Use a short TTL (1 hour) for non-fingerprinted assets + client-side swap via postMessage. See security and streaming considerations for pop-ups and live activations for operational practices and threat models (Security & Streaming for Pop‑Ups).
2) Flash sale campaign
For marketing-controlled campaigns, pre-generate packs for each campaign creative during deploy. Fingerprint asset filenames and update the manifest/wrapper HTML so the change propagates instantly with immutable caching. For tips on running flash campaigns that coordinate timed assets, see guides on flash sale campaigns.
3) Stock ticker/finance feed
For high-frequency changes (e.g., stock went up/down), avoid regenerating images every second. Instead, use a small set of prebuilt icons (up / down / neutral) and switch the linked favicon URL in the DOM via JS when an event arrives. This minimizes churn while still signaling state. Real-time auction and finance update patterns offer useful analogies for minimizing churn (live auction optimization).
Browser quirks & platform notes (2026)
- Chrome/Edge: honor
link rel="icon"changes immediately when the URL changes; manifest changes require versioning. - Safari (iOS): ignores many PWA manifest features; iOS still prefers
apple-touch-iconand caches aggressively—fingerprint or change filename to force update. - Firefox: supports maskable icons; monitors cache headers closely—ETag helps.
- PWAs: Add maskable icons and a 512px PNG/WEBP; include related_applications if you provide native apps. For design patterns and microapp integration, see composable UX pipelines.
Security and performance considerations
- Sanitize uploaded master images and avoid executing image content—use built-in WP sanitizers.
- Limit generation concurrency to avoid CPU spikes (queue regeneration for high-scale sites).
- Prefer CDN/S3 for serving generated assets—offload bandwidth from origin and get better cache controls; edge caching strategies are essential for scale (edge caching playbook).
- Use modern formats (AVIF/WebP) as supplemental icons where supported to save bytes; still include PNG fallback for widest support.
- Protect REST endpoints: monitor and harden against automated abuse — see approaches for using predictive AI to detect automated attacks (using predictive AI).
Advanced tips
- For on-the-fly overlays (e.g., real-time ticker numbers), use a sprite or canvas in the admin preview instead of regenerating files.
- When using Analytics, tag favicon-driven clicks (tab-recovery page opens) so teams can measure impact of micro cues.
- Use feature flags to enable/disable dynamic favicons for A/B tests—measure lift carefully.
2026 trends to watch
- Micro-interactions continue to be a low-friction way to regain attention; expect more native features for adaptive icons across OSes in 2026.
- Privacy-first platforms may limit some cross-site signals—favor on-site REST-driven updates rather than third-party tag chains.
- More teams will move icon generation into CI for deterministic assets; serverless image generation (Edge functions) is becoming standard in 2026.
Example project links & templates
Drop this plugin into a sandbox WordPress install and experiment with three scenarios: live stream (toggle meta), campaign (pre-generate), and ticker (switch prebuilt icons). For production, move generated assets to a CDN and use fingerprinting for immutable cache headers. For packaging and field-friendly builds, reviews of portable streaming and capture kits may be useful when producing masters (portable streaming kits).
Actionable checklist
- Create a high-res master icon (1024–2048px) and add it to your media library.
- Install the dynamic-favicons plugin (or paste the skeleton above into a plugin file).
- Decide on a caching strategy: fingerprinted files or versioned querystrings.
- Hook generation into your deploy pipeline (WP-CLI or CI job) — see production and CI playbooks for guidance (production playbook).
- Test updates across Chrome, Firefox, Safari and iOS—check manifest behavior.
- Measure impact with analytics and iterate.
Final notes
Dynamic favicons are a high-ROI, low-risk channel for signaling live events and campaigns. In 2026, with more attention to micro UX and PWA adoption, automated favicon packs and correct caching are essential. Use server-side generation for brand-compliant images, fingerprint assets for caching, and rely on small client-side swaps for very high-frequency changes. For streaming and pop-up-specific operational patterns, see practical guides on security and streaming for pop-ups (security & streaming).
Call to action
Ready to automate favicons across your WordPress fleet? Download the example plugin, CI scripts and manifest templates from our repo and run the WP-CLI commands in your staging environment. If you’d like, paste your use-case (live stream, flash sale, ticker) and we’ll provide a tailored implementation checklist—fast.
Related Reading
- Edge Caching Strategies for Cloud‑Quantum Workloads — The 2026 Playbook
- Security & Streaming for Pop‑Ups: A 2026 Playbook for Safe Hybrid Activation
- Compact Streaming Rigs & Night‑Market Setups: Field Guide
- Flash Sale Survival Kit: Practical Tips for Campaigns
- Build a Compact Home Studio on a Budget: Mac mini M4 + Accessories That Don’t Break the Bank
- When Geopolitics Meets Mining: Could Greenland Become a Crypto Hub (and What U.S. Moves Mean)?
- Halal & Nostalgic: How 2016-Throwback Beauty Launches Fit Modest Beauty Routines
- Ad Creative That Drives Link-in-Bio Clicks: Lessons from Ads of the Week
- Takedown Workflow Template: Removing Nonconsensual AI Images From Platforms Quickly
Related Topics
Unknown
Contributor
Senior editor and content strategist. Writing about technology, design, and the future of digital media. Follow along for deep dives into the industry's moving parts.
Up Next
More stories handpicked for you
Integrating Favicon.live with Edge AI Deployments: A Raspberry Pi 5 Example
Security Checklist: Locking Down Favicon Sources to Prevent Supply-Chain Tampering
Template Pack: Favicons for Map, Food, and Local Discovery Micro-apps
Changelog Idea: Adding Creator Attribution Fields to Favicon Manifests
Roadmap Post: Support for Animated SVG Favicons and Live Badges
From Our Network
Trending stories across our publication group