# Self-Host Google Fonts Used by Your Theme and Plugins

> Detects Google Fonts stylesheets loaded on your site, lets you download them to your own server from Tools > Local Google Fonts, and then serves the local copies so visitors' browsers never contact Google.

- Type: PHP
- Runs: Run everywhere
- Category: [Privacy & Cookies](https://wpide.com/library/category/privacy/)
- Tags: google-fonts, gdpr, fonts
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/privacy-self-host-google-fonts/

## Code

```php
add_filter( 'style_loader_src', function ( $src ) {
    if ( ! is_string( $src ) || false === strpos( $src, 'fonts.googleapis.com' ) ) {
        return $src;
    }

    $key   = md5( html_entity_decode( $src ) );
    $local = (array) get_option( 'wpide_local_gfonts', array() );

    if ( ! empty( $local[ $key ] ) ) {
        $uploads = wp_get_upload_dir();
        return $uploads['baseurl'] . '/wpide-fonts/' . $key . '.css';
    }

    $found = (array) get_option( 'wpide_found_gfonts', array() );
    if ( ! isset( $found[ $key ] ) && count( $found ) < 20 ) {
        $found[ $key ] = html_entity_decode( $src );
        update_option( 'wpide_found_gfonts', $found, false );
    }

    return $src;
}, 99 );

add_filter( 'wp_resource_hints', function ( $urls ) {
    if ( ! get_option( 'wpide_local_gfonts' ) ) {
        return $urls;
    }

    return array_filter( $urls, function ( $url ) {
        $href = is_array( $url ) ? ( isset( $url['href'] ) ? $url['href'] : '' ) : $url;
        return false === strpos( $href, 'fonts.gstatic.com' ) && false === strpos( $href, 'fonts.googleapis.com' );
    } );
}, 99 );

add_action( 'admin_menu', function () {
    add_management_page( 'Local Google Fonts', 'Local Google Fonts', 'manage_options', 'wpide-local-fonts', function () {
        $found   = (array) get_option( 'wpide_found_gfonts', array() );
        $local   = (array) get_option( 'wpide_local_gfonts', array() );
        $uploads = wp_get_upload_dir();
        $dir     = trailingslashit( $uploads['basedir'] ) . 'wpide-fonts';

        if ( isset( $_POST['wpide_font_key'] ) && check_admin_referer( 'wpide_local_fonts' ) && current_user_can( 'manage_options' ) ) {
            $key = sanitize_key( wp_unslash( $_POST['wpide_font_key'] ) );

            if ( isset( $found[ $key ] ) && wp_mkdir_p( $dir ) ) {
                $agent    = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36';
                $response = wp_safe_remote_get( set_url_scheme( $found[ $key ], 'https' ), array( 'timeout' => 15, 'user-agent' => $agent ) );
                $css      = wp_remote_retrieve_body( $response );
                $ok       = 200 === wp_remote_retrieve_response_code( $response ) && false !== strpos( $css, '@font-face' );

                if ( $ok && preg_match_all( '#url\((https://fonts\.gstatic\.com/[^)]+)\)#', $css, $m ) ) {
                    foreach ( array_unique( $m[1] ) as $font_url ) {
                        $file = $key . '-' . md5( $font_url ) . '.' . pathinfo( wp_parse_url( $font_url, PHP_URL_PATH ), PATHINFO_EXTENSION );
                        $get  = wp_safe_remote_get( $font_url, array( 'timeout' => 15, 'stream' => true, 'filename' => $dir . '/' . $file ) );
                        if ( is_wp_error( $get ) || 200 !== wp_remote_retrieve_response_code( $get ) ) {
                            $ok = false;
                            break;
                        }
                        $css = str_replace( $font_url, $uploads['baseurl'] . '/wpide-fonts/' . $file, $css );
                    }
                }

                if ( $ok && false !== file_put_contents( $dir . '/' . $key . '.css', $css ) ) {
                    $local[ $key ] = time();
                    update_option( 'wpide_local_gfonts', $local, false );
                    echo '<div class="notice notice-success"><p>Fonts downloaded. Your site now serves them locally.</p></div>';
                } else {
                    echo '<div class="notice notice-error"><p>The fonts could not be downloaded. Check that your server can reach fonts.googleapis.com.</p></div>';
                }
            }
        }

        echo '<div class="wrap"><h1>Local Google Fonts</h1>';
        if ( ! $found ) {
            echo '<p>No Google Fonts detected yet. Visit some pages of your site, then come back.</p></div>';
            return;
        }
        echo '<table class="widefat striped"><thead><tr><th>Stylesheet</th><th>Status</th><th></th></tr></thead><tbody>';
        foreach ( $found as $key => $url ) {
            echo '<tr><td><code>' . esc_html( $url ) . '</code></td><td>' . ( isset( $local[ $key ] ) ? 'Served locally' : 'Loaded from Google' ) . '</td><td>';
            echo '<form method="post">';
            wp_nonce_field( 'wpide_local_fonts' );
            echo '<input type="hidden" name="wpide_font_key" value="' . esc_attr( $key ) . '">';
            submit_button( isset( $local[ $key ] ) ? 'Download again' : 'Download and serve locally', 'secondary small', 'submit', false );
            echo '</form></td></tr>';
        }
        echo '</tbody></table></div>';
    } );
} );
```

## Notes

Visit a few front-end pages first so the fonts are detected; fonts loaded with @import inside a theme stylesheet are not detected.

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find "Self-Host Google Fonts Used by Your Theme and Plugins" in its snippet library and add it in one click; or create a new PHP snippet in WPIDE (or any code snippets plugin) and paste the code above. More snippets: https://wpide.com/library/
