3

I am using WordPress along with Autoptimize and Cloudflare, and using Locally hosted fonts. I can't leverage browser caching on my site.

I tried using Cloudflare Page rules to Leverage 1 year browser caching on all resources.

It worked, and most of my site was getting cached EXCEPT FONTS.

I know fonts are heavy and can have negative impact on performance.

I tried the following code in htaccess file in my server root.

# Fonts
# Add correct content-type for fonts
AddType application/vnd.ms-fontobject .eot 
AddType application/x-font-ttf .ttf
AddType application/x-font-opentype .otf
AddType application/x-font-woff .woff
AddType image/svg+xml .svg

<IfModule mod_expires.c>
    ExpiresActive on
    ExpiresDefault "access plus 2 days"
    ExpiresByType application/vnd.ms-fontobject "access plus 1 year"
    ExpiresByType application/x-font-ttf "access plus 1 year"
    ExpiresByType application/x-font-opentype "access plus 1 year"
    ExpiresByType application/x-font-woff "access plus 1 year"
    ExpiresByType application/font-woff2  "access plus 1 year"
</IfModule>
# END Expire headers

# BEGIN Cache-Control Headers
<ifModule mod_headers.c>
    <filesMatch "\.(ico|jpe?g|png|gif|swf|mp4|mov|css|js|json|woff|woff2)$">
        Header add Cache-Control "public"
    </filesMatch>
    <filesMatch "\.(x?html?|php)$">
        Header add Cache-Control "private, must-revalidate"
    </filesMatch>
</ifModule>

But it didn't work.

As far as I know the below above code should have done the trick to cache the Fonts and JSON.

Please help me figure out the correct way to implement it.

Warnings about fonts not being cached:

Leverage browser caching of static assets: 91/100 Learn More WARNING - (2.0 days) - https://milyin.com/superpwa-manifest.json

Leverage browser caching of static assets: 91/100 Learn More WARNING - (2.0 days) - https://milyin.com/wp-content/uploads/omgf/neve-google-font-poppins/poppins-normal-700.woff2

WARNING - (2.0 days) - https://milyin.com/wp-content/uploads/omgf/neve-google-font-poppins/poppins-normal-400.woff2

WARNING - (2.0 days) - https://milyin.com/wp-content/uploads/omgf/neve-google-font-poppins/poppins-normal-500.woff2

0

2 Answers 2

8

Your mime types don't match your ExpireByType directives:

$ curl --head https://milyin.com/wp-content/uploads/omgf/neve-google-font-poppins/poppins-normal-700.woff2
...
expires: Thu, 09 Sep 2021 13:24:15 GMT
...
content-type: font/woff2

So you should change your .htaccess. Instead of, or in addition to

ExpiresByType application/font-woff2  "access plus 1 year"

you should have

ExpiresByType font/woff2  "access plus 1 year"

Here are the correct mime types for fonts:

$ grep font /etc/mime.types 
application/font-sfnt               otf ttf
application/font-tdpfr              pfr
application/font-woff               woff
application/vnd.font-fontforge-sfd                      sfd
application/vnd.ms-fontobject                           eot
application/x-font              pfa pfb gsf
application/x-font-pcf              pcf pcf.Z
font/collection                 ttc
font/otf                    ttf otf
font/sfnt                   ttf otf
font/ttf                    ttf otf
font/woff                   woff
font/woff2                  woff2

You could use a wildcard rule like:

ExpiresByType font/* "access plus 1 year"
2
  • Hey, Thanks for answering. Could you please advice about the JSON file too, which was not caching as mentioned in the question body. Sep 7, 2021 at 15:05
  • 2
    You could add ExpiresByType application/json "access plus 1 year" to cover all json files. Fonts are almost never dynamically generated or likely to change. JSON on the other hand serves many purposes. Be sure that All your JSON is actually static content before you allow it to be cached for such a long time. Sep 7, 2021 at 15:09
6
ExpiresDefault "access plus 2 days"
ExpiresByType application/vnd.ms-fontobject "access plus 1 year"
ExpiresByType application/x-font-ttf "access plus 1 year"
ExpiresByType application/x-font-opentype "access plus 1 year"
ExpiresByType application/x-font-woff "access plus 1 year"
ExpiresByType application/font-woff2  "access plus 1 year"

You need to determine what mime-type your server is actually using to serve these files by checking the Content-Type HTTP response header. It is this that determines what mime-type you should be using in the ExpiresByType directive. Looking at one of your .woff2 requests, it returns:

content-type: font/woff2

So you would need to use the following instead:

ExpiresByType font/woff2  "access plus 1 year"

above code should have done the trick to cache the Fonts and JSON

But the above code does not explicitly do anything for JSON? (And the .json file you link to seems to result in a 404?) The expected mime-type for JSON is application/json, but again, check your server's response headers if you are using mod_expires.

UPDATE: Your server is responding with an application/json mime-type for .json requests so you need to add the appropriate ExpiresByType directive if you want to cache these files for longer. (However, do you really want to cache JSON files for long periods? JSON files are more likely to be fairly dynamic, not static?)

I tried using Cloudflare Page rules to Leverage 1 year browser caching on all resources.

It worked, and most of my site was getting cached EXCEPT FONTS.

Although your .htaccess directives actually set everything else to be cached for just 2 days (not 1 year). And Cloudflare is seemingly able to override this.

You are employing "service workers" on your site, which is resulting in a great deal of client-side "caching". It's hard to tell which requests are being served by Cloudflare?


UPDATE:

# BEGIN Cache-Control Headers
<ifModule mod_headers.c>
    <filesMatch "\.(ico|jpe?g|png|gif|swf|mp4|mov)$">
        Header set Cache-Control "public"
    </filesMatch>
    <filesMatch "\.(css)$">
        Header set Cache-Control "public"
    </filesMatch>
    <filesMatch "\.(js)$">
        Header set Cache-Control "private"
    </filesMatch>
    <filesMatch "\.(x?html?|php)$">
        Header set Cache-Control "private, must-revalidate"
    </filesMatch>
</ifModule>

You should change the set argument in the above header directives to add instead. Otherwise, these will likely override the Cache-Control headers set by mod_expires (which are set earlier). Indeed, for these resources there are no Cache-Control: max-age directives in the response as you would otherwise expect (set by mod_expires).

These Header directives don't target .woff2 and .json files. (Why not?)

Aside: I'm also wondering why you are setting .css requests to public and .js requests to private? Why do you need to differentiate the two?

15
  • 1
    Thanks. And oh yes, I changed the url of the JSON. I updated the question, and the url for it is milyin.com/superpwa-manifest.json Sep 7, 2021 at 13:57
  • 1
    Well, Cloudflare was supposed to catch everything from milyin.com* and set the Browser Cache to 1 year... Anyways I changed it to 1 week now... Hopefully that'll be good for WordPress.. What you say Sep 7, 2021 at 13:58
  • 1
    @AdityaAgarwal The JSON file is being served with the application/json mime-type - as I suggested in my answer - so you would need to add an additional ExpiresByType rule for this.
    – MrWhite
    Sep 7, 2021 at 15:07
  • 1
    Thank You. Will try Sep 7, 2021 at 15:09
  • 1
    Changing it to "1 week" is not necessarily going to resolve the issue (some of these resources, especially fonts, should be cached for longer). Your site is also using "service workers", so the response you are seeing may not be coming directly from Cloudflare. You should probably update your Header directives as well. I've updated my answer.
    – MrWhite
    Sep 7, 2021 at 16:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.