Add Favicons to Next JS from Headless WordPress

Last Updated:
Headless Wordpress, Favicons and Next JS

This post contain affiliate links to Udemy courses, meaning when you click the links and make a purchase, I receive a small commission. I only recommend courses that I believe support the content, and it helps maintain the site.

Every help article and piece of content I have read about using WordPress favicons in Next JS all ended with ‘and then add the files directly to your /public folder’.

Not super helpful. I want to dynamically pull the favicon files from WordPress, and inject them into Next JS. I do not want to have to do anything manually. The plan is build once, roll out to multiple websites.

Note: This article expects your WordPress instance to include the WP GraphQL plugin, and to understand how to fetch data in getStaticProps.

Favicons on the WordPress side

In WordPress 3.4 the Customizer Panel was added to the ‘Appearance -> Customize’ admin screen. This functionality allows the user to make live changes to their site. Changes include updating the title, tagline, and site icon (favicon).

Rather than adding any custom code to WordPress, it makes sense to use this already existing functionality. Allow a user to upload a 512px by 512px PNG to the Customizer Site Logo, and let the media library take care of any image resizing.

By default WordPress will create all the additional image sizes we need from the original 512×512 image.

Register the Site Icon with WP GraphQl

The first step is to register the customizer site icon field with WP GraphQl. This will then allow us to query it in Next JS.

To register the field, add the following code to your functions.php file.

function headless_add_favicon_query() {
	register_graphql_field( 
		'RootQuery', 
		'favicon', 
		[
		'type' => 'MediaItem',
			'description' => __( 'Favicon set in the customizer', 'YOUR_TEXT_DOMAIN ),
			'resolve' => function() {

				$icon_id = get_option( 'site_icon' );

				if ( ! isset( $icon_id ) || ! absint( $icon_id ) ) {
					return null;
				}

				$media_object = get_post( $icon_id );
				return new \WPGraphQL\Model\Post( $media_object );
			}
		] 
	); 
}
add_action( 'graphql_register_types', 'headless_add_favicon_query' );

Now if you look in the GraphQL IDE and query the following you will return the site icon and all its sizes:

query faviconQuery {
  favicon {
    mediaDetails {
      sizes {
        sourceUrl
        width
      }
    }
  }
}

Get the WordPress Favicon into Next JS

This article expects you to already have some sort of auth flow set up for making requests to your WordPress instance. The below walks through the basic set up for grabbing the data. On a production site it should be properly protected.

import Head from 'next/head';
import fetch from 'isomorphic-unfetch';

export default function SomePage({ favicon }) {
    // Other page code.

    // Loop through the favicon array and set up each link.
    return (
        <Head>
            {favicon?.length > 0 &&
                favicon.map(({ width, sourceUrl }) => {
                    if (width === '180') {
                        return (
                            <link
                                key={`fav-${width}x${width}`}
                                rel="apple-touch-icon"
                                href={sourceUrl}
                                sizes={`${width}x${width}`}
                            />
                        );
                    }
                    return (
                        <link
                            key={`fav-${width}x${width}`}
                            rel="icon"
                            type="image/png"
                            sizes={`${width}x${width}`}
                            href={sourceUrl}
                        />
                    );
                })}
        </Head>
    );
}

export async function getStaticProps() {
    const res = await fetch('YOUR_WORDPRESS_WPGRAPHQL_URL', {
        body: JSON.stringify({
            query: `
                    query {
                        favicon {
                            mediaDetails {
                                sizes {
                                    sourceUrl
                                    width
                                }
                            }
                        }
                    }
                `
        })
    });

    const data = await res.json();

    return {
        props: {
            favicon: data?.favicon?.mediaDetails?.sizes || []
        }
    };
}

 

Hopefully this helped you, and if you have any questions you can reach me at: @robertmars

Related Posts

Helpful Bits Straight Into Your Inbox

Subscribe to the newsletter for insights and helpful pieces on React, Gatsby, Next JS, Headless WordPress, and Jest testing.