I have an F on Yslow, because of expired headers.

I have tried all the solutions from similar question and only got partial success.

Here's my .htaccess file:

# BEGIN WordPress

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

<IfModule mod_expires.c>
### activate mod_expires
ExpiresActive On
### Expire .gif’s 1 month from when they’re accessed (Default algorithm)
ExpiresByType image/gif A2592000
### Expire .jpg’s 1 month from when they’re accessed
ExpiresByType image/jpg A2592000
### Expire .png’s 1 month from when they’re accessed
ExpiresByType image/png A2592000
### Expire .js’s 7 days from when they’re accessed (Alternative algorithm)
ExpiresByType text/js "access plus 7 days"
### Expire .css’s 30 days from when they’re accessed
ExpiresByType text/css "access plus 30 days"
### Expire everything else 1 day from when it’s last modified
ExpiresDefault "modification plus 1 day"


<IfModule mod_deflate.c>
    SetOutputFilter DEFLATE
    <IfModule mod_setenvif.c>
        # Netscape 4.x has some problems...
        BrowserMatch ^Mozilla/4 gzip-only-text/html

        # Netscape 4.06-4.08 have some more problems
        BrowserMatch ^Mozilla/4.0[678] no-gzip

        # MSIE masquerades as Netscape, but it is fine
        # BrowserMatch bMSIE !no-gzip !gzip-only-text/html

        # NOTE: Due to a bug in mod_setenvif up to Apache 2.0.48
        # the above regex won't work. You can use the following
        # workaround to get the desired effect:
        BrowserMatch bMSI[E] !no-gzip !gzip-only-text/html

        # Don't compress images
        SetEnvIfNoCase Request_URI .(?:gif|jpe?g|png)$ no-gzip dont-vary

<IfModule mod_headers.c>
  <filesmatch "\.(ico|flv|jpg|jpeg|png|gif|css|swf)$">
  Header set Cache-Control "max-age=2678400, public"
  <filesmatch "\.(html|htm)$">
  Header set Cache-Control "max-age=7200, private, must-revalidate"
  <filesmatch "\.(pdf)$">
  Header set Cache-Control "max-age=86400, public"
  <filesmatch "\.(js)$">
  Header set Cache-Control "max-age=2678400, private"


# END WordPress

You seem to have a few issues with your current config file:

  1. You are trying to use both mod_expires and mod_headers to set the same cache headers (but with different values?). mod_expires sets the max-age parameter of the Cache-Control header, as well as the older Expires header. This is likely to result in conflict (particularly since you are trying to set different values with each). mod_headers is likely to win. Using mod_expires is preferable. However, if you need to set specific Cache-Control headers then you will need to use mod_headers.

  2. ExpiresByType text/js "access plus 7 days"
    Your server is unlikely responding with a text/js mime-type for JavaScript files. So, this probably isn't doing anything. Check what mime-type your server is sending and specify that. It's probably application/javascript.

  3. The <IfModule mod_headers.c> container is inside the <IfModule mod_deflate.c> container?

  4. Remove the <IfModule> wrappers. Any errors? The <IfModule> wrappers are only required if your site should function correctly without these modules installed (if you are moving your site from server to server), or if certain directives from another module are dependent on a particular module being installed. If you use <IfModule> wrappers around everything then your system simply fails silently when the module is not installed, rather than alerting you to an error. So, it might simply be failing silently. An error is usually preferable!

  5. As Stephen pointed out in comments, if you have all these directives within the # BEGIN..END WordPress comments then they are likely to be overwritten with the next WP update.

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.