Skip to content

My Sites: Fall back to plain favicon when no Site Icon is present - #116

Open
wprashed wants to merge 1 commit into
WordPress:mainfrom
wprashed:fix/114-mysites-favicon-fallback
Open

My Sites: Fall back to plain favicon when no Site Icon is present#116
wprashed wants to merge 1 commit into
WordPress:mainfrom
wprashed:fix/114-mysites-favicon-fallback

Conversation

@wprashed

Copy link
Copy Markdown

Summary

Fixes #114.

Sites recorded through wp-admin alone, or themes that hardcode a plain favicon instead of utilizing WordPress Site Icon markup, do not have a stored iconUrl in their My Sites record and previously displayed the fallback globe icon permanently.

Changes

  • In MySiteRow (src/popup/components/MySites.js), if site.iconUrl is not present, attempt to render the site's standard ${origin}/favicon.ico.
  • If an onError event fires for the active icon, fallback to ${origin}/favicon.ico (if attempting a custom icon) or the globe icon when no favicon can be loaded.
  • Rebuilt popup production bundles and synced Safari resources.

Testing Instructions

  1. Run npm test or node test/smoke.js.
  2. In the popup, inspect a My Sites row for a site without an explicit Site Icon URL and verify it attempts loading ${origin}/favicon.ico before falling back to the globe icon.

When a site record has no stored Site Icon URL, attempt to load the site's default /favicon.ico before falling back to the globe icon.

Fixes WordPress#114.

@i-am-chitti i-am-chitti left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for picking it up. I gone through the changes and here are two notes. Not a maintainer here, so please read these as suggestions rather than blockers.

  • 10up.com, the example in #114, is not be covered completely: its /favicon.ico returns an nginx 404 currently, and the real icon sits at a theme path in <link rel="shortcut icon">. It does emit an apple-touch-icon, which detect.js already accepts (L123-L125), so that row may fill in on its own after one logged-in front-end visit.

const { origin, key } = site;
const baseUrl = site.baseUrl || origin;
const iconUrl = site.iconUrl || null;
const defaultFavicon = origin ? `${origin}/favicon.ico` : null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since origin drops the install path, two installs on one host - example.com/client1 and example.com/client2 - would both request https://example.com/favicon.ico, and a subdirectory multisite child would pick up the main site's icon. Records are keyed at the install base for that reason (#94), so would baseUrl from 73 fit better here? It's always set (site.baseUrl || origin), so the guard could go with it:

Suggested change
const defaultFavicon = origin ? `${origin}/favicon.ico` : null;
const defaultFavicon = `${baseUrl}/favicon.ico`;

For subdirectory installs that mostly falls through to the globe rather than finding an icon - core registers the favicon.ico rewrite only when the install is at the domain root - though that seems kinder than showing a different site's icon.

const baseUrl = site.baseUrl || origin;
const iconUrl = site.iconUrl || null;
const defaultFavicon = origin ? `${origin}/favicon.ico` : null;
const [activeIcon, setActiveIcon] = useState(iconUrl || defaultFavicon);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this copies a prop into state, and the initializer only runs once. Rows keep their instance across store updates (keyed by site.key, L44), so if a later login captures the Site Icon through upsertOnLogin, the row re-renders while activeIcon still holds the old URL. The new icon would then appear only after the popup is reopened. iconFailed behaves the same way.

A reset covers both:

useEffect(() => { setActiveIcon(iconUrl || defaultFavicon); setIconFailed(false); }, [iconUrl, defaultFavicon]);

@wprashed

Copy link
Copy Markdown
Author

Thanks for the review and note, @i-am-chitti! Exactly as you pointed out, for sites with apple-touch-icon or standard sized Site Icon markup, detect.js captures siteIconUrl on front-end visits. For sites recorded purely via wp-admin or without sized icon links, trying /favicon.ico at render time provides a display-only best-effort fallback before showing the globe icon, keeping detection and storage untouched as outlined in #114.

@Xilonz

Xilonz commented Aug 28, 2026

Copy link
Copy Markdown

@wprashed you can also try to get the favicon directly from the browser: https://developer.chrome.com/docs/extensions/how-to/ui/favicons

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

My Sites: fall back to the site's plain favicon when no Site Icon was captured

3 participants