Wordpress - Why does it say: 'Cookies are blocked or not supported'?
When you log in to the admin WordPress sets cookies (in PHP) to keep you logged in while you navigate around your site. If this fails, you get the error message, "Cookies are blocked or not supported by your browser."
This could fail in a couple different ways, but before we dig into those situations, let's take a look at the source of these error messages:
wp-login.php
v5.1.1
if ( empty( $_COOKIE[ LOGGED_IN_COOKIE ] ) ) {
if ( headers_sent() ) {
$user = new WP_Error(
'test_cookie',
sprintf(
/* translators: 1: Browser cookie documentation URL, 2: Support forums URL */
__( '<strong>ERROR</strong>: Cookies are blocked due to unexpected output. For help, please see <a href="%1$s">this documentation</a> or try the <a href="%2$s">support forums</a>.' ),
__( 'https://codex.wordpress.org/Cookies' ),
__( 'https://wordpress.org/support/' )
)
);
} elseif ( isset( $_POST['testcookie'] ) && empty( $_COOKIE[ TEST_COOKIE ] ) ) {
// If cookies are disabled we can't log in even with a valid user+pass
$user = new WP_Error(
'test_cookie',
sprintf(
/* translators: %s: Browser cookie documentation URL */
__( '<strong>ERROR</strong>: Cookies are blocked or not supported by your browser. You must <a href="%s">enable cookies</a> to use WordPress.' ),
__( 'https://codex.wordpress.org/Cookies' )
)
);
}
}
Failure Context
1. LOGGED_IN_COOKIE
check
If the LOGGED_IN_COOKIE
is missing, something has gone wrong and we cannot continue. This is the first indication there's a problem. The code then checks for 2 more specific issues to clarify the error message returned.
2. headers_sent
check
The first test is for headers_sent
which is a core PHP function to determine whether or not your response headers have been put together and sent back to the user making the request. They should not be sent by this point. If they are, you have a problem that needs to be resolved before a user can log in.
This is also the least commonly addressed case for most issues raised here for this question. It also generates a slightly different error message.
Cookies are blocked due to unexpected output.
3. Test Cookie status
In this test, WordPress tried setting a test cookie and that failed. Notice that the check is for both the POST
request parameter and missing cookie. The POST
parameter comes from a hidden field on the login form: <input type="hidden" name="testcookie" value="1" />
. The cookie name default is wordpress_test_cookie
, but can be changed via the TEST_COOKIE
constant. More on this in a bit.
This is the most common scenario. Something has gone wrong that prevents either the POST
parameter from being set or the test cookie from being set.
Let's take a look at the scenarios that could cause this to happen.
Common Problems and Solutions
1. Your browser blocks cookies
This is the original intention of these checks. It's common for browsers to block "unsafe" cookies or common trackers. It's even pretty common for most people to block cookies altogether and only allow certain cookies to be set after they're discovered (or not at all). This is why the error message is worded this way.
Solution: enable cookies in your browser.
2. Your site is sending headers prematurely
Somewhere in your code you probably have a call to send headers like this: header('Location: https://google.com/');
(for example). Sending a header this way can kill off the process of building the entire header before sending it as a response. I'm not going to go into more detail here because you'd also get a different error message. Read more: Login page error cookies are blocked due to unexpected output.
Solution: check that you're not sending headers prematurely.
3. Cookies aren't being saved
This is the most common situation developers run into, especially when migrating sites.
setcookie( $name , $value, $expires );
Cookies are fairly simple. They typically have a name, value, and time when they expire. The rest of the parameters are usually left to the defaults.
setcookie( $name , $value, $expires, $path, $domain, $secure, $httponly );
WordPress explicitly sets these defaults for path, domain, and protocol. If these aren't 100% correct, the cookie just disappears. This is for security. You wouldn't want cookies you set on your site to be available to anyone else, otherwise someone could access your site admin and WordPress authentication would be worthless.
NOTE: Path is the base path the cookie is available from. If it's set to
/
, then it will be available to the entire site. If it's set to/wp-admin
, only urls that start with/wp-admin
will be able to access it. For example, you would not see it on your site's homepage.
Solution: This is a bit more complicated. Let's take deeper dive.
The test cookie
`wp-login.php v5.1.1
$secure = ( 'https' === parse_url( wp_login_url(), PHP_URL_SCHEME ) );
setcookie( TEST_COOKIE, 'WP Cookie check', 0, COOKIEPATH, COOKIE_DOMAIN, $secure );
if ( SITECOOKIEPATH != COOKIEPATH ) {
setcookie( TEST_COOKIE, 'WP Cookie check', 0, SITECOOKIEPATH, COOKIE_DOMAIN, $secure );
}
First, WordPress is checking your login url to see if it's using https or not. $secure
is being used to set the cookie to respond to http or https requests, not both.
Cookie constants
Next, we have to look into some of these constants that are muddying the waters.
COOKIEPATH
and SITECOOKIEPATH
determine the path the cookie is available from. SITECOOKIEPATH
overrides COOKIEPATH
. Keep this in mind. This will be important later.
COOKIE_DOMAIN
determines the domain the cookie is available from, eg yourdomains.com
. If it's set to false, it will use the current domain.
ADMIN_COOKIE_PATH
isn't in the source above, but will get used later. Bear with me on this one. This is the path to your WordPress dashboard.
These constants are set by WordPress, but can be changed. Let's take a look at the source.
/wp-includes/default-constants.php
v5.1.1
if ( ! defined( 'COOKIEPATH' ) ) {
define( 'COOKIEPATH', preg_replace( '|https?://[^/]+|i', '', get_option( 'home' ) . '/' ) );
}
if ( ! defined( 'SITECOOKIEPATH' ) ) {
define( 'SITECOOKIEPATH', preg_replace( '|https?://[^/]+|i', '', get_option( 'siteurl' ) . '/' ) );
}
if ( ! defined( 'ADMIN_COOKIE_PATH' ) ) {
define( 'ADMIN_COOKIE_PATH', SITECOOKIEPATH . 'wp-admin' );
}
if ( ! defined( 'TEST_COOKIE' ) ) {
define( 'TEST_COOKIE', 'wordpress_test_cookie' );
}
Now we're starting to get some clarity.
COOKIEPATH
uses your home url stored in your database. This is typically set in your wp-config.php
file as the constant WP_HOME
.
SITECOOKIEPATH
overrides COOKIEPATH
(remember?) and that comes from your site url stored in the database. In your wp-config.php
file this is your WP_SITEURL
constant.
If these don't match, there's a chance you'll have a problem.
This is why you see people recommend setting these with a server parameter:
define('WP_SITEURL', 'https://' . $_SERVER['HTTP_HOST']);
define('WP_HOME', 'https://' . $_SERVER['HTTP_HOST']);
This configuration makes sure your site responds with the correct domain. It works in most cases, but should be used cautiously.
Disclaimer: You should always do a search/replace in your database for old urls and change these to your new url. Please don't think the above will fix everything. It won't.
Debugging cookies
In order to debug this issue, try outputting these constants on your wp-login.php
page like this:
add_action( 'login_init', 'my_login_init' );
function my_login_init() {
echo '<b>Cookie path:</b> ';
var_dump( COOKIEPATH );
echo '<br /><b>Cookie site path:</b> ';
var_dump( SITECOOKIEPATH );
echo '<br /><b>Cookie domain:</b> ';
var_dump( COOKIE_DOMAIN );
echo '<br /><b>Admin cookie path:</b> ';
var_dump( ADMIN_COOKIE_PATH );
}
This will give you a good idea of what parameters are being used to set your cookies. If these don't match your site's settings or your expectations, you need to address it to ensure your cookie is being set correctly.
You can set these explicitly in your wp-config.php
file:
// False setting for the domain uses the current domain.
define('COOKIE_DOMAIN', false);
// Setting to / will only work if your site is set to the root domain.
define('COOKIEPATH', '/');
define('SITECOOKIEPATH', '/');
Authorization cookies
All the above have to do with the test cookie which is the source of the error message, but there's one more step beyond that: your authorization cookies.
WordPress sets a bunch of cookies, depending on the context. For logging in, you'll need these:
'wordpress_logged_in_' . COOKIEHASH
- and either
'wordpress_' . COOKIEHASH
or'wordpress_sec_' . COOKIEHASH
These cookies need to have the right path, protocol and domain or you won't be able to log in.
Fortunately, most of those checks are taken care of with the test cookie we already looked at. The only difference is with the admin path:
define( 'ADMIN_COOKIE_PATH', SITECOOKIEPATH . 'wp-admin' );
If the path to your admin is different than yourdomain.com/wp-admin
, you need to set this in your wp-config.php
file like this:
define( 'ADMIN_COOKIE_PATH', '/path/to/wp-admin' );
Conclusion
This is a complicated problem. There are multiple causes for what appears to be the same issue.
If you get this error, you will have to do some debugging to find out what's going on. Here are some suggestions:
- Always check your browser first. Make sure it's able to save cookies from PHP.
- If you recently migrated, check for old urls in your database, then check your
wp-config.php
settings. - If you moved your WordPress admin, you must set your admin path cookie in
wp-config.php
. - Check your cookie paths, domains, and protocols to make sure they match.
- Make sure you're not sending headers prematurely.
- Check to make sure a caching layer like Varnish or CDN like Cloudflare allows you to set cookies and bypass cache both in the admin and through the login process.
Best of luck!