justinholtweb / craft-fav
Favicons for Craft CMS — upload one square image in the control panel and Fav generates every icon a browser, a phone and a pinned tile ask for, then puts the right tags in every page.
Package info
github.com/justinholtweb/craft-fav
Type:craft-plugin
pkg:composer/justinholtweb/craft-fav
Requires
- php: ^8.2
- ext-json: *
- craftcms/cms: ^5.3.0
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-08-29 12:53:20 UTC
README
Fav
Favicons for Craft CMS 5 — one image in, every icon a browser asks for out.
Upload one square image in the control panel. Fav generates the .ico, the PNGs, the iOS home
screen icon, the Windows tile, the web manifest and the tile config, then puts the tags for them
in the head of every page. No template changes, no build step, no dependencies, no third-party
favicon generator to paste twelve files back from.
It is free, in one edition, with everything switched on.
Requirements
Craft CMS 5.3+ and PHP 8.2+.
Installation
From the Plugin Store, or:
composer require justinholtweb/craft-fav php craft plugin/install fav
What comes out of one image
| File | What wants it |
|---|---|
favicon.ico |
16, 32 and 48px in one file — browser tabs, bookmarks, crawlers, link unfurlers |
favicon-16x16.png … favicon-96x96.png |
Modern browsers, which prefer a PNG when offered one |
icon.svg |
Copied through when the source is an SVG, for tab strips on high-density screens |
apple-touch-icon.png |
The iOS home screen, at 180px, flattened onto your background colour |
icon-192.png, icon-512.png |
Android launchers and install prompts, through the manifest |
mstile-150x150.png |
Windows pinned tiles |
manifest.json |
The two icons above and your two colours |
browserconfig.xml |
The tile, and its colour |
Set the theme colour, the background colour, the tile colour and an optional padding, and Fav does the rest. Each site in a multi-site install has its own set.
Where the tags go
By default Fav splices them into every front-end HTML page, just before </head>. Nothing to add
to a template.
A page whose template already declares an icon of its own is left alone, so a hand-built head keeps working. Turn that off in the settings if you would rather Fav's tags were added anyway — they go in last, which is the copy the browser keeps.
To place them yourself:
{{ craft.fav.tags() }}
Calling that stands the automatic injection down for the page it runs on, so nothing appears twice. Also available:
{{ craft.fav.tagList() }} {# the tags as a list, to place individually #}
{{ craft.fav.url('apple-touch-icon.png') }} {# a URL, for an Open Graph image or an email #}
{{ craft.fav.favicon().themeColor }} {# the set itself, for its colours #}
/favicon.ico
Browsers, crawlers and link unfurlers ask the site root for /favicon.ico by name whether or not
a page links to one. Fav answers it. Craft only sees the request when there is no real file at
that path, so a favicon somebody put in the web root still wins.
The control panel
Fav also replaces the control panel's own favicon with the primary site's, so a browser window full of control panels tells you which client you are looking at. Off by default.
Where the files live
Generated files go in web/fav/<site uid>/ and are served by the web server as ordinary static
files. If the web root is not writable — a read-only deploy, a containerised production box — they
go to storage/fav/ instead and are served through Craft, and everything else works the same.
Because they live outside the database, a fresh deployment has the settings but not the files:
php craft fav/favicons/generate # every site, only what is out of date php craft fav/favicons/generate default # one site php craft fav/favicons/generate --force # rebuild regardless php craft fav/favicons/status # what each site has, and whether it is current php craft fav/favicons/clear # delete the generated files, keep the settings
Replacing the source image in the assets index regenerates the set on the spot, so the tab does not keep showing last year's logo.
Source images
A square PNG, 512×512 or larger, with transparency if the artwork has any. A non-square image is contained rather than cropped — a wide logo is never sliced to make it fit.
An SVG works too, and is copied through as a vector icon as well as being rasterised, but only on servers running Imagick. GD cannot rasterise vector artwork, and its failure is a blank PNG rather than an error, so Fav refuses it and says so on the screen.
Settings
| Setting | Default | What it does |
|---|---|---|
autoInject |
true |
Add the tags to front-end pages automatically |
skipPagesWithIcons |
true |
Leave pages that already declare an icon alone |
serveRootIcon |
true |
Answer /favicon.ico |
applyToCp |
false |
Use the primary site's favicon in the control panel |
regenerateOnAssetSave |
true |
Rebuild when the source image changes |
cacheDuration |
604800 |
Seconds a browser may cache an icon served through PHP |
All of them can be set in config/fav.php.
Already running a PWA plugin?
Turn Fav's web manifest off for that site. Two <link rel="manifest"> tags in one head is one
too many, and the PWA's is the one that has to win — it carries the start URL and display mode
that make the site installable. Fav's manifest deliberately carries neither.
Permissions
One: Manage favicons. Anyone without it does not see the section.
Licence
MIT.