I’ve always been scared of creating PHP cookies. Cookies are an extremely widely used web technology consisting of little pieces of data that live on your device and remember things: for example, the last product you browsed on Amazon, or whether you’re already logged-in to Gmail. As common as they are, though, cookies have always felt like a spooky piece of web architecture that I presumed would be painful and complex to implement.
Then a client project came up that needed cookies, and guess what? They’re easy to write—much easier than, for example, baking cookies, which I still refuse to learn.
In this article, we’ll walk you through why, and how, to use cookies in WordPress.
Why Use PHP Cookies?
There are times when user account creation is too clunky a means to store persistent user data. Cookies can persist user data without requiring a login.
Websites have lots of user-specific data. A site might want to know all kinds of things to improve my user experience: my native language, the last time I visited, form information I’ve previously submitted, and so on. In many cases, this data needs to persist: it needs to last across site visits.
The most common way WordPress uses to persist data about site visitors is through WordPress user accounts. This system is really full-featured, with all kinds of user roles, permissions, data, metadata, and so on.
There are times, though, when it’s a bit too clunky. By default, it requires users to create an account—complete with, at minimum, a username, email, and password—and then log into that account. To just store a bit of very data (like, say, a user language preference or time zone), that’s an awful lot. Cookies can persist user data without requiring a login.
WordPress’s inbuilt cookie system works through its user system, and that’s not what we want. So here we’re kicking it old-school, with pure PHP that we wrap into a plugin.
Features
This solution takes user input and saves it persistently. If you come back to the page in the same browser a week from now, it’ll still store the last answer you gave.
As you can imagine, this would be excellent for remembering lots of things about individual users—like their most recently read articles, their progress through an e-learning course, or what products they’ve browsed on your site—without them needing to create a WordPress user account.
How it Works
Here is the full code (also available on GitHub). Don’t get overwhelmed: we’re going to break it down to its most important elements, but here’s the whole thing first.
<?php
/*
Plugin Name: WPShout Cookie Demo
Description: A demo of PHP cookies in a WordPress environment.
Author: WPShout
Author URI: https://wpshout.com
*/
/*
* Setting and retrieving cookie
*/
add_action( 'init', 'wpcd_set_cookie', 1 );
function wpcd_set_cookie() {
if(isset( $_POST[ 'fave_food' ] ) ) :
$cookie_value = sanitize_text_field( $_POST[ 'fave_food' ] );
setcookie( wpcd_get_cookie_name(), $cookie_value, time() + (86400 * 999), "/" ); // 86400 = 1 day
// Now refresh so the header changes get captured
header("Refresh:0");
exit;
endif;
}
function wpcd_get_cookie_name() {
return 'fave_food';
}
function wpcd_get_cookie() {
return $_COOKIE[ wpcd_get_cookie_name() ];
}
function wpcd_is_cookied() {
return isset( $_COOKIE[ wpcd_get_cookie_name() ] );
}
/*
* Displaying cookie value and form through shortcodes
*/
add_shortcode( 'cookie_demo', 'wpcd_show_cookie_result' );
function wpcd_show_cookie_result() {
ob_start();
if( wpcd_is_cookied() ) :
echo 'Your most recent favorite food was ' . wpcd_get_cookie() . '!';
else :
echo 'You haven\'t yet told us your favorite food!';
endif;
return ob_get_clean();
}
add_shortcode( 'cookie_form', 'wpcd_show_cookie_form' );
function wpcd_show_cookie_form() {
ob_start(); ?>
<form method="post">
<label for="name">Fave Food:<label><br><input type="text" name="fave_food" placeholder="Cookies" />
<p><input type="submit"></p>
</form>
<?php return ob_get_clean();
}
About the Shortcodes
The second half of this code—beginning Displaying cookie value and form through shortcodes
—is important, but it’s not the part we really want to teach.
What we’re doing here is creating two WordPress shortcodes:
- A shortcode that creates a form to let users submit information to be cookied.
- A form to display the cookied information.
Note that you don’t need users to submit their information. You can just as easily log it yourself—for example, the time of day they last accessed the site. For simplicity here, though, our cookie is user-submitted.
These two shortcodes let us host our demo code quite simply inside the WordPress post editor:
If you need to know more about writing WordPress shortcodes, see here for a general introduction. If you’d like to know more about our use of the ob_start()
and ob_get_clean()
functions, check David’s excellent tutorial on output buffering for shortcodes.
The Cookie Functions
After the shortcodes, we’re left with the following functions:
add_action( 'init', 'wpcd_set_cookie', 1 );
function wpcd_set_cookie() {
if(isset( $_POST[ 'fave_food' ] ) ) :
$cookie_value = sanitize_text_field( $_POST[ 'fave_food' ] );
setcookie( wpcd_get_cookie_name(), $cookie_value, time() + (86400 * 999), "/" ); // 86400 = 1 day
// Now refresh so the header changes get captured
header("Refresh:0");
exit;
endif;
}
function wpcd_get_cookie_name() {
return 'fave_food';
}
function wpcd_get_cookie() {
return $_COOKIE[ wpcd_get_cookie_name() ];
}
function wpcd_is_cookied() {
return isset( $_COOKIE[ wpcd_get_cookie_name() ] );
}
Let me explain them, in a sensible order:
wpcd_get_cookie_name()
This lets us centralize the cookie’s name—fave_food
—in one place, so it’s simple to change if we ever want to. A simple way to write DRY (Don’t Repeat Yourself) code.
wpcd_is_cookied()
This checks if the fave_food
cookie exists, in two steps:
- It retrieves the cookie’s name via
wpcd_get_cookie_name()
- It asks whether that exists in the PHP
$_COOKIE
PHP superglobal.
$_COOKIE
is an array of cookies that currently exist for the current page load. As a superglobal, it’s always accessible in PHP, much like other familiar variables such as $_POST
and $_GET
(used for processing form submissions in HTML and PHP).
wpcd_get_cookie()
This function is similar to wpcd_is_cookied()
, but it returns the cookie value itself, rather than whether the cookie value exists.
wpcd_set_cookie()
This is the function that actually sets the cookie. Here’s what it does, in order:
- It checks whether the
$_POST
superglobal has an element calledfave_food
. This is true whenever someone has just submitted the “favorite food” form we created in the plugin’s shortcode section. - If we do have a form submission, we sanitize it and save the result as the variable
$cookie_value
. - Now we’re ready to actually set the cookie with PHP’s function
setcookie()
.
How to Use setcookie()
setcookie()
takes a number of arguments. Understanding these is all there is to understanding the function itself. Arguments, in order, are:
- The cookie’s name, which we fetch using
wpcd_get_cookie_name()
.
The value the cookie we should take, which is $cookie_value
.
- How long the cookie will live before it expires, expressed as a number of seconds from now. I’ve decided that the cookie should live 999 days from now. We can get the time right now with PHP’s
time()
function; and since there are 86,400 seconds in a day, this argument takes the value oftime() + 86400 * 999
. - Where the cookie will be accessible.
"/"
makes it accessible across the entire WPShout site.
After We’ve Set the Cookie…
Because both $_COOKIE
and $_POST
live as HTTP headers, we need to refresh the page for our changes to $_COOKIE
to show up. That’s what header("Refresh:0");
does. And since we don’t want more PHP processing to happen after we’ve just demanded that the page refresh, we call exit
to stop all further PHP from executing.
Demo Summary
There’s a fair amount of code here, but all the cookie-related heavy lifting is done by two functions: setcookie()
, and retrieving the cookie value with $_COOKIE[ $name ]
, where $name
points to the cookie’s name as a string.
Enjoy PHP Cookies!
If you’ve understood the demo above, you’re now ready to create persistent data for your users, without needing to put them through the full WordPress user login experience—a very useful thing to be able to do.
If you have any questions about the demo, don’t hesitate to ask, and thanks for reading!
[…] it stands to reason that last week’s article on writing PHP cookies in WordPress has a big asterisk about caching. In particular, the full-page […]
Just a quick note: The correct way of setting cookies in WP is this:
setcookie( 'true_cookie', 1, time()+3600*24*100, COOKIEPATH, COOKIE_DOMAIN );
Last two constants ensures that things will work in any possible configuration. Your sample will only work if the WP is installed in the root directly.
Hi Fred! Thanks for sharing this nifty technique. This might be a dumb question (it’s probably a dumb question) but if I put in something other than “Cookies” in the demo and submit, shouldn’t the demo field display whatever I submitted the next time I load this page?
Hi Sasha, Not a dumb question at all! 🙂 The cookie changes what shows up in the “Your most recent favorite food was ___” line below the form.
I’d meant to make that line bold to be attention-getting, but missed that when I published—it should be a bit more prominent now.
Does that make sense?
Makes total sense! However, no matter how many times I submit a new answer I’m still being told that I haven’t told you what my favorite food is. Just a glitch on my side (Chrome 45.0.2454.101 m / Windows 10)?
Hi Sasha,
You’re right! The issue is how the cookie interacts with our site’s caching – which turns out to be quite an issue with cookies in general. (I wasn’t noticing it because I was logged-in, and so not seeing the cached version of the site.)
I’ll write a fix for this up for next week. Thank you!
Fred
Hi Fred,
Phew! And here I thought I might be insane 🙂 Looking forward to reading about the update next week and finding ways to incorporate this nifty feature in my client work.
All the best,
Sasha
Sounds good. 🙂 In the meantime, I’ve adjusted the caching, so this post should work as advertised if you try it now. (Let me know?)
Thanks!
Fred
It does indeed!! Very cool 🙂