WordPress Super Cache and Setting Cookies

WP Super Cache and PHP Cookies Don’t Mix

WP Super Cache and Cookies

Website Development Challenge: Setting PHP Cookies While Using WP Super Cache

Solution: Set the cookie using Javascript

When I created the First Touch Referral Tracking plugin, it seemed like it should be pretty straight forward: check for a cookie with a referrer and set a cookie with the referrer if there’s not one. Then, simply grab the cookie whenever it’s needed and calculate a referral coupon code.

So, I wrote the code using PHP’s setcookie() function, put it place, and tested it. Everything worked like a charm…until I logged out of my WordPress admin account. That’s when I noticed some really strange things happening. Most notably, when I was not logged in as an admin, the cookie did not set. After a few hours of narrowing down the problem, I pinpointed WP Super Cache as the culprit.

The Issue in Detail

The issue is that by default WP Super Cache loads different pages to admins than non-logged-in visitors. For a non-logged-in visitor, Super Cache serves up a cached page, like it’s supposed to, in order to save your server work and round trips between the visitor’s computer and your website.

This means:

  • Plugins in wp-super-cache/plugins/ are loaded *before* any of WordPress is
  • PHP setcookie() will not work correctly with Super Cache “out of the box”
  • Cookies and WP Super Cache can work together, you just have to change some stuff

To get the referrer, I used $_Server[‘HTTP_REFERER’]

When my plugin ran without being logged in this was the rough sequence of events:

  1. Page begins loading
  2. WP Super Cache returns page
  3. My plugin grabs the $_Server[‘HTTP_REFERER’] and sets it in the cookie
  4. Other WordPress plugins run
  5. Page is returned to the visitor

This meant that the referrer was always my root domain. Regardless of where I actually came from, because Super Cache loads first, the last referrer is now my domain.

So, the question became, “How do I set a cookie before WP Super Cache loads?”

The solutions

Luckily, a few other developers had encountered this same WP Super Cache cookie issue and pointed me in the right direction, although some of what worked for them didn’t work for me, hence the reason for writing this post.

The solution that ultimately worked for me was option 5 here: setting the cookie using JavaScript.

Option 1—Turn off Super Cache

If you’re having a big enough issue and need a specific functionality, unless Super Cache is really helping you out, ditch it.

Option 2—Write your plugin in WP Super Cache’s plugin area instead of WordPress’s

WP Super Cache gives the option to use a specially created cache plugin area to make it play nice with other WordPress plugins. When you use the super cache plugin area, it will load those plugins first.

This uses the commands do_cacheaction() and add_cacheaction(). You can see the specs on how to use these here.

For some reason unknown to me, after re-writing my plugin to be a Super Cache plugin, it still didn’t solve the problem.

Option 3—Use the Super Cache “Half-On” option and edit wp-cache-phase1.php before line 110

A good post on the WordPress Hackers mailing list by William Canino gives instructions on how to edit the phase1.php file to set the cookie earlier:

header( 'WP-Super-Cache: WP-Cache' );
// <-- add your Cookie-setting PHP here. Go nuts.
if ( $meta[ 'dynamic' ] ) {
include($cache_file);
} else {
readfile( $cache_file );
}
die();

Again, for some reason, this did not work for me.

Option 4—Edit your .htaccess file

Michael Kimb Jones’ post WP Cache and Cookies do not mix details getting rid of the offending .htaccess code.

Most of us though, cannot choose to ditch the .htaccess details. So, others on the Internet (I can’t find their posts now) say that simply adding the name of your cookie to the list of super cache cookies in the .htaccess file fixes the problem 95% of the time.

It looks like this:

RewriteEngine On
RewriteBase /


RewriteCond %{REQUEST_METHOD} !=POST
RewriteCond %{QUERY_STRING} !.*=.*
RewriteCond %{HTTP_COOKIE} !^.*(comment_author_|wordpress|wp-postpass_).*$
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/supercache/%{HTTP_HOST}/$1/index.html.gz -f
RewriteRule ^(.*) /wp-content/cache/supercache/%{HTTP_HOST}/$1/index.html.gz [L]


RewriteCond %{REQUEST_METHOD} !=POST
RewriteCond %{QUERY_STRING} !.*=.*
RewriteCond %{QUERY_STRING} !.*attachment_id=.*
RewriteCond %{HTTP_COOKIE} !^.*(comment_author_|wordpress|wp-postpass_).*$
RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/supercache/%{HTTP_HOST}/$1/index.html -f
RewriteRule ^(.*) /wp-content/cache/supercache/%{HTTP_HOST}/$1/index.html [L]


RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

Specifically at issue are the 2 lines with HTTP_COOKIE in them:
RewriteCond %{HTTP_COOKIE} !^.*(comment_author_|wordpress|wp-postpass_).*$

The theory is that if you add your cookie name to the list you should be good to go: “(comment_author_|wordpress|wp-postpass_|your-cookie-name-here)”

However, this also did not work for me.

Option 5—Set the cookie using Javascript

This is the one that worked for me.

Setting a cookie in Javascript takes place apart from Super Cache. This means that the page loads completely, the browser keeps the http_referer we want intact, then we set the cookie with that information.

To use this method:

  • Write the JavaScript to get, check, and set the cookie (see examples at w3schools.com)
  • Write the plugin to use the cookie in PHP
    • Once the cookie is set by JavaScript you can now use PHP isset() and $_COOKIE to retrieve it for your purposes
    • Use wp_enqueue_script to point to your JavaScript file
    • Use add_action(‘init’,’your-function-name-here) to load your JavaScript file at initialization

Conclusions

  1. It takes some extra work to get cookies, http_referer, and WP Super Cache to work together, but it is possible.
  2. There are several possible solutions.
  3. My recommendation is to set the cookie using JavaScript, thereby bypassing Super Cache

I hope you found this post helpful. If so, follow me on Twitter here, or fan me on Facebook here.

Don’t hesitate to contact me if you have questions or other suggestions. You can also leave a reply below.

Aloha.

Comments

  1. Hi,

    i’ve try the javascript solutions but don’t work for me… i’ve add this functions but the cookie are created after php, this is the code:

    function setCookieTracking(){
    wp_enqueue_script(‘function’, get_template_directory_uri().’/js/test.js’);
    var_dump($_COOKIE);
    }
    add_action(‘init’,’setCookieTracking’);

    What’s wrong?
    Thanks

  2. Ngoai Ngu Phuong Dong says:

    I can setcookie via PHP and can see it via chrome or firefox. But when i using php code isset($_COOKIE[‘your_name’]) it always return false. If i disabled wp_supper_cache it worked perfect.

    So very difficult to mix PHP cookie with wordpress super cache.