How do I reference favicons in my /public-folder?

Hi
I’m trying to add favicons to my theme. In the old days, I could simply just edit the head.blade.php file. Now everything seems to be more complex (at least for me)

I have this in my bud config:

.assets([
      {
        from: app.path("@src/images"),
        to: app.path("@dist/@file"),
      },
      {
        from: app.path("@src/images/favicons"),
        to: app.path("@dist/favicons/@file"),
      },
    ])

Bud then creates /public/favicons. But all the filenames in here are hashed.

Som when I try to reference the filenames like this in setup.php (which not working because the blade syntax isn’t working here):

function add_favicons()
{
?>
    <link rel="apple-touch-icon" sizes="180x180" href="@asset('apple-touch-icon.png')">
    <link rel="icon" type="image/png" sizes="32x32" href="@asset('favicon-32x32.png')">
    <link rel="icon" type="image/png" sizes="16x16" href="@asset('favicon-16x16.png')">
    <link rel="manifest" href="@asset('site.webmanifest')">
<?php
}
add_action('wp_head', __NAMESPACE__ . '\\add_favicons');

So how do I reference these icons in setup.php? Or is there an other method?

For my favicon/app icon needs I use the RealFaviconGenerator WordPress plugin:

WordPress now has its own Favicon/Site icon setting that can be set in the backend/admin web UI, however, it doesn’t has as many different variants and isn’t as customizability as the RealFaviconGenerator (plugin).

There had been one caveat with the RealFaviconGenerator plugin, though, which also answers how to handle Favicons in WordPress core natively:

Programmatically, WordPress has for some time now a dedicated filter for the favicon (get_site_icon_url):

That filter is used by the core logic for intercepting HTTP requests to the favicon, among other favicon-related things.
If you want to go the programmatic route, you can use the asset(...) function in Sage 10 to get an URL to the favicon (e.g. that can be passed to the aforementioned get_site_icon_url filter):

use function Roots\asset;
// [...]
$favicon_url = asset('favicon.ico')->uri();
// [...]

Hi Strasis
OK. I tried the plugin-solution and it worked.

But Where should I add the $favicon_url snippet if I wanted to do it without a plugin?
I just get en error if I put it in setup.app
**Fatal error** : Uncaught Error: Call to undefined function app() in /Users/bo/sites/radar/vendor/roots/acorn/src/Roots/helpers.php:20 Stack trace: #0 /Users/bo/sites/radar/vendor/roots/acorn/src/Roots/globals.php(6): Roots\asset('favicon.ico') #1 /Users/bo/sites/radar/web/app/themes/radar/app/setup.php(281): asset('favicon.ico') #2 /Users/bo/sites/radar/web/wp/wp-includes/template.php(770): require_once('/Users/bo/sites...') #3 /Users/bo/sites/radar/web/wp/wp-includes/template.php(716): load_template('/Users/bo/sites...', true, Array) #4 /Users/bo/sites/radar/web/app/themes/radar/functions.php(59): locate_template('app/setup.php', true, true) #5 /Users/bo/sites/radar/vendor/illuminate/collections/Traits/EnumeratesValues.php(245): {closure}('app/setup.php', 0) #6 /Users/bo/sites/radar/web/app/themes/radar/functions.php(65): Illuminate\Support\Collection->each(Object(Closure)) #7 /Users/bo/sites/radar/web/wp/wp-settings.php(566): include('/Users/bo/sites...') #8 /Users/bo/sites/radar/web/wp-config.php(9): require_once('/Users/ in **/Users/bo/sites/radar/vendor/roots/acorn/src/Roots/helpers.php** on line **20**

This appears to be the same issue as this very recent one:

This article may be interesting:
https://www.sitepoint.com/all-you-need-to-know-about-the-new-wordpress-site-icon-api/
WordPress already adds HTML for the site icon, as with
https://developer.wordpress.org/reference/functions/wp_site_icon/

So just using the get_site_icon_url may already result in the HTML you need.

Ha, that was easy. Ok. So I don’t need the plugin. This is much simpler. Thanks again :slight_smile:

Well, technically yes, the core site icon feature is sufficient.
The plugin offers additional icons and customization options though.

+1 for RealFaviconGenerator, it’s the best. I’ve been using the website and plugin for many years without issue.

I am using wonderful realfavicon generator but I prefer to use it programmatically instead of the plugin.

But I have a problem I don’t know how to solve. I use the asset function in index.php:

  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" type="image/svg+xml" href="<?= asset('images/favicon/favicon.svg') ?>">
    <link rel="icon" type="image/png" href="<?= asset('images/favicon/favicon.png') ?>">
    <link rel="icon" type="image/png" sizes="32x32" href="<?= asset('images/favicon/favicon-32x32.png') ?>">
    <link rel="icon" type="image/png" sizes="16x16" href="<?= asset('images/favicon/favicon-16x16.png') ?>">
    <link rel="apple-touch-icon" sizes="180x180" href="<?= asset('images/favicon/apple-touch-icon.png') ?>">
    <link rel="manifest" href="<?= asset('images/favicon/site.webmanifest') ?>">
    <link rel="mask-icon" href="<?= asset('images/favicon/safari-pinned-tab.svg') ?>" color="#d19393">
    <link rel="shortcut icon" href="<?= asset('images/favicon/favicon.ico') ?>">
    <meta name="msapplication-TileColor" content="#97a8c6">
    <meta name="msapplication-config" content="<?= asset('images/favicon/browserconfig.xml') ?>">
    <meta name="theme-color" content="#97a8c6">
    <?php wp_head(); ?>
  </head>

The problem comes with browserconfig.xml and site.webmanifest that contain a link to the icon, which is hashed, and I cannot use the asset function with.

Ideally, the favicons should be the only images not hashed so we can reference them without using asset function. What would be the way to do this?

But you could generate the browserconfig.xml and site.webmanifest files dynamically, hence still being able to use the asset(...) function to resolve the asset hashes.
The alternative would be avoiding filename hashes alltogether, but those are used for cache busting.

After checking possible steps involving adding extensions to webpack and bud, I concluded the simple solution is to place the favicon folder in the root of Wordpress and just reference everything there without hash. The icons are optimized by realfavicongenerator anyway.
Realfavicongenerator even recommends to place favicon.ico and apple-touch-icon.png in the root of the website as it’s a fallback, so I think I will stick to this practice unless I see it’s overly simplistic in the long run.

I was working on this today and came up with the following script that generates an icon.json manifest file with hashed icon file paths from manifest.json. This is running in a sage-inspired custom theme using Bud.js. Would love to see a bud-powered solution.

// package.json

"scripts": {
      "build": "bud build && node app/build/icons.js"
  }
// icons.js

/**
 * Generate icons.json manifest file for Android devices
 * This script is run via `npm run build`
 * The generated file is saved to the public directory and loaded in <head>
 */
import fs from 'fs';
import * as url from 'url';
import manifest from '../../public/manifest.json' assert {type: 'json'};

// Get hashed icon path
const getIcon = (size) => {
    return manifest['images/favicon-' + size + '.png'];
}

// File data
const fileData = {
    "icons": [
      { "src": getIcon(192), "type": "image/png", "sizes": "192x192" },
      { "src": getIcon(512), "type": "image/png", "sizes": "512x512" }
    ]
}

// Get current directory path
const dirname = url.fileURLToPath(new URL('.', import.meta.url));

// Generate icons.json file and save to public directory (same as manifest.json)
fs.writeFile(
    dirname + '../../public/icons.json',
    JSON.stringify(fileData),
    function(error) {
        if (error) {
            return console.log(error);
        }
        console.log('Successfully generated icons.json.');
    }
);
1 Like

As bud is using webpack, this webpack-specific plugin may be also interesting:

A bud extension for favicons (that uses that webpack plugin or your implementation) would be a great addition!

2 Likes

Cool script @esaner, and great idea @strarsis. I’ve quickly wrapped the webpack plugin into an extension. It’s pretty rough, but does work.

Hopefully not stepping on anyones toes (sorry if so).

npm install bud-favicon

3 Likes