Book Now
Advanced Technical SEO

Adding a Cookie Pop-up Without Plugins

How to add pop-up Cookies without third party plugins

Adding a Cookie Pop-up Without Plugins
Author:
Carlos Sánchez
Topics:
Technologies
Publication Date:
2024-08-28

Last Review:
2024-08-28

Due to current legislation in most countries, to use tools that allow the analysis of user interaction on the website (if restrictions become too tight, we may end up using logs to gather statistics), a pop-up is required on all websites where the user consents to receiving cookies.

Cookies are not only used for analytics purposes but also for identifying the user and providing them with a better, more personalised experience on the website.

However, in this post, I will focus on making cookie consent work with code. Many plugins add unnecessary JS and CSS and are mainly concerned with pushing you to buy the premium version, so let's see how we can avoid that dependency.

Code to Add a Cookie Policy

First, I'll explain the basic code so that it can be adapted to any web environment.

POP-UP

In a module that repeats throughout our website, preferably in the "footer" so as not to block the main content, we will create the pop-up. We will add an extra feature to this pop-up: it will only exist on our website if cookies have not been accepted. Why would we want a pop-up with a display none if cookies have already been accepted?

We will achieve this with !isset($_cookie[].

<?php
if
(!isset($_COOKIE['accept_cookies'])) {
?>
<link rel='stylesheet' id='cookies-css' href='{YOUR CSS FILE PATH}' media='all' />";
<div id="cookieConsentContainer" data-nosnippet>
<div style="color:white">We use cookies to ensure that we give you the best experience on our website. Here is our <a rel="nofollow" href="/privacy-policy/" style="color:grey">privacy policy</a></div>
<div>
<button id="rejectCookies">Reject</button>
<button id="acceptCookies">Accept</button>
</div>
</div>
<script id="cookies-js" src="{YOUR JS FILE PATH}" defer></script>
<?php
}

For efficiency, I have used external JS and CSS files in the example, but it would work the same with internal files. The IDs and classes used are just examples.

Not understanding this?
If you need help with the more technical aspects, book a consultancy session with me: Get real SEO help!

As is evident, the most important part of the POP-UP is that it functions correctly, and for that, we need JavaScript.

JavaScript

Basically, this code activates the cookie function for the user if they accept it and displays the request to accept them again after a minute if they reject it. All these parameters can be changed to suit your needs.

document.addEventListener("DOMContentLoaded", function(){
var consent = getCookie("accept_cookies");
if (!consent) {
document.getElementById("cookieConsentContainer").style.display = "flex";
}
document.getElementById("acceptCookies").addEventListener("click", function(){
setCookie("accept_cookies", true, 365);
document.getElementById("cookieConsentContainer").style.display = "none";
location.reload(); // Reloads the page
});
document.getElementById("rejectCookies").addEventListener("click", function(){
setCookie("reject_cookies", true, 1);
document.getElementById("cookieConsentContainer").style.display = "none";
setTimeout(function() {
document.getElementById("cookieConsentContainer").style.display = "flex";
}, 60000); // 60,000 milliseconds = 1 minute
});
});
function setCookie(name, value, days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days*24*60*60*1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}
function getCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}

There is an unnecessary conversion to "Display: none;" when cookies are accepted. I encourage you to find it.

Making the Cookies Do Something

It’s great to have a notice, but we’ll need to give the user something once they accept the cookies.

In the section where we need it, for example in the "<head>", we can add the necessary analytics tools, such as Google Analytics:

<?php
if (isset($_COOKIE['accept_cookies'])) {
// Google Analytics
?>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id={USER_ID}">
</script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '{USER_ID}');
</script>
<?php
}
?>

All measurement tools should be added here, such as Metrika, Hotjar, or Clarity. These can also be combined with a delay if you don't want it to significantly impact website performance and don't mind if the bounce rate isn’t accurately recorded with these heat map and user behaviour tools.

If I receive many requests, I will explain how to make this process optimal when using Google Tag Manager.

Adding CSS

Although this would suffice, to make the work easier, I’m adding some simple CSS for visual appearance.

#cookieConsentContainer {
position: fixed;
bottom: 0;
z-index: 10;
min-height: 112px;
display: flex;
align-items: center;
background-color: rgba(253, 253, 253, 0.9);
color: black;
font-size: 14px;
padding: 0 32px;
width: 100%;
margin: auto;
justify-content: center;
flex-direction: column;
}
#acceptCookies {
background-color: var(--secondary);
font-weight: bold;
color: var(--lightgrey);
}
#rejectCookies {
color:rgb(44, 45, 45);
}
#acceptCookies, #rejectCookies {
font-size: 14px;
margin: 7px;
padding: 5px 20px;
cursor: pointer;
border-radius: 50px;
border: none;
}

How to Apply It to WordPress

Although I’m hesitant to explain things for WordPress, it remains the most widely used CMS, so I feel obliged to adapt this for WordPress enthusiasts.

You can do it via the functions.php file or by creating your own plugin.

Not understanding this?
If you need help with the more technical aspects, book a consultancy session with me: Get real SEO help!

So, it would be the same application but with the addition of Hooks.

You would encapsulate both the POP-UP code and the code to make cookies do something within a Hook.

How does it work? This function adds all that code to the footer.

function add_cookie_notice_footer() {
// The pop-up code
}
add_action('wp_footer', 'add_cookie_notice_footer');

And with this other function, you can add the analytics code to the header.

function add_cookie_track_header() {
// The analytics code
}
add_action('wp_head', 'add_cookie_track_header');

How It Would Look in My Own Plugin

Here is an advanced example. This code is not for copying and pasting; it will only make sense if you read and understand the previous sections.

<?php
function add_cookie_notice_footer() {
$noCookiePopup = isset($_GET['noCookiePopup']) && $_GET['noCookiePopup'] == 'true';
// This greyed-out part only makes sense if you read the article about the bot that automatically accepts cookies
$autoAcceptCookies = isset($_GET['utm_term']) && $_GET['utm_term'] == 'seobots';

if ($autoAcceptCookies && !isset($_COOKIE['accept_cookies'])) {

setcookie('accept_cookies', '1', time() + (86400 * 30), "/"); // 86400 = 1 day

$_COOKIE['accept_cookies'] = '1'; // Also set the superglobal variable for the rest of the script execution

}

if (!isset($_COOKIE['accept_cookies']) && !$noCookiePopup) {
$mi_plugin_url = plugin_dir_url( __FILE__ );
echo "<link rel='stylesheet' id='cookies-css' href='" . $mi_plugin_url . "css/cookies.css' media='all' />";
?>
<div id="cookieConsentContainer" data-nosnippet>
<div style="color:var(--white)">We use cookies to ensure that we give you the best experience on our website. Here is our <a rel="nofollow" href="https://carlos.sanchezdonate.com/politica-privacidad/" style="color:var(--grey)">privacy policy.</a></div>
<div>
<button id="rejectCookies">Reject</button>
<button id="acceptCookies">Accept</button>
</div>
</div>
<?php
}
}
add_action('wp_footer', 'add_cookie_notice_footer');
function add_cookie_track_header() {
if (isset($_COOKIE['accept_cookies'])) {
// Insert tracking code here, as shown above
}
}
add_action('wp_head', 'add_cookie_track_header');
?>

Not understanding this?
If you need help with the more technical aspects, book a consultancy session with me: Get real SEO help!

Additional Information

Google Chrome will make a significant change regarding how third-party cookies affect the browser (not the search engine).

On the other hand, and in contrast, the AEPD has published a guide on cookies for web traffic measurement, which may legally exempt companies in Spain from needing to obtain consent for installing analytical cookies on visitors' devices. This information was provided by Pablo Moratinos and confirmed by Ubaldo Hervás.

Update 28-08-2024: Google has again delayed the end of third-party cookies in Chrome.

How Chrome's New Cookie Policy Will Affect You

Google Chrome has restricted third-party cookies for 1% of users as a trial in its browser, with the intention of implementing it fully by the end of 2024.

This means that first-party cookies (such as those used by websites for carts or registered users) will continue to work.

Google has suggested certain options or solutions for privacy-preserving alternatives.

CHIPS

CHIPS, also known as partitioned cookies, is a technology that allows developers to store third-party cookies in a partitioned manner (i.e., in different parts), restricting access only to the top-level site context where they were initially set, to improve privacy and prevent cross-site tracking.

For example, you have the domain example.com, but the backend or structure of what you have to establish that service is at chart.example.com. In this case, a good way to implement cookies, even if using a third-party API to establish charts, would be this.

A partitioned third-party cookie is tied to the top-level site where it was initially set and cannot be accessed from other places.

The goal is to allow cookies to be set by third-party services, but only read within the context of the top-level site where they were initially set.

This blocks cross-site tracking, while still allowing non-tracking uses of third-party cookies, such as maintaining the state of embedded maps or chat widgets across different sites, and persisting configuration information for CDN load balancing and headless CMS providers (when using a WordPress or Shopify backend, for example, but with a powerful front-end framework in JS).

Note: Chrome has a maximum limit of 180 cookies per partition that cannot exceed 10 KB per embedded site.

Currently only supported by Chromium-based browsers like Chrome or Edge.

In browsers that support CHIPS, a new attribute for the HTTP Set-Cookie header is provided — Partitioned — which allows site owners to opt to use CHIPS:

Set-Cookie: __Host-example=34d8g; SameSite=None; Secure; Path=/; Partitioned;

Partitioned cookies must be set with Secure, and it is recommended to use the __Host prefix to bind them to the hostname rather than the registrable domain​​.

With Partitioned set, the cookie is stored using two keys: the host key and a new partition key based on the scheme and eTLD+1 of the top-level URL that the browser was visiting when the request was made to the endpoint URL that set the cookie​​.

For example, if a user visits https://shoppy.example, which embeds a third-party chat service from https://3rd-party.example/chat to provide support, https://3rd-party.example/chat sets a cookie on the user’s device using Partitioned to maintain the chat state across different subdomains of the site. If the user visits several subdomains that also embed https://3rd-party.example/chat, the new embedded instances can access the cookie because the partition key matches​​.

Regarding browser support, CHIPS is being developed with the goal of becoming an open web standard and is under discussion in the PrivacyCG. It has undergone a 7-month origin trial, during which the Chrome team received useful feedback, working with key stakeholders to explore that feedback and resulting in an updated design that better serves the web ecosystem​​.

Implementing CHIPS with PHP

To implement CHIPS in PHP, you should set the Partitioned attribute in the Set-Cookie header when sending the cookie:

<?php
$cookie_value = '34d8g';
setcookie('__Host-example', $cookie_value, [
'expires' => time() + 3600, // 1 hour lifetime
'path' => '/',
'domain' => 'your-domain.com', // Change to your domain
'secure' => true, // Important for CHIPS
'httponly' => true, // Recommended for security
'samesite' => 'None', // Necessary for third-party cookies
'partitioned' => true, // Attribute for CHIPS
]);
?>

Difference Between Partitioned and Non-Partitioned

The main difference between partitioned and non-partitioned cookies is that partitioned cookies have an additional partition key based on the top-level URL, which restricts their access to that specific context and prevents cross-site tracking. Non-partitioned cookies, on the other hand, do not have this restriction and can be accessed by any site that shares the domain.

Using an Optional Partitioning Model

The optional partitioning model is used to balance user privacy with website functionality. It allows websites to continue using third-party cookies for legitimate functions, such as chat services or embedded maps, while blocking cross-site tracking.

Storage Access API

The Storage Access API essentially makes third-party cookies for iframes embedded in the website behave like first-party cookies.

That is, it offers a way for cross-site content loaded in a third-party context (i.e., embedded in an <iframe>) to gain access to third-party cookies that it would normally only have access to in a first-party context. This is relevant for user agents that, by default, block access to third-party cookies to enhance privacy (for example, to prevent tracking). The API provides methods that allow embedded resources to check if they currently have access to third-party cookies and, if not, to request access from the user agent.

The name can be confusing because it only provides access to cookies and not to other client-side storage mechanisms, such as Web Storage or IndexedDB.

Browsers implement various storage access features and policies that restrict access to third-party cookies. These range from giving embedded resources under each top-level origin a unique cookie storage space (partitioned cookies) to completely blocking access to cookies when resources are loaded in a third-party context. The goal is to protect user privacy and security, preventing their activity from being tracked across different sites and making them less vulnerable to exploits like cross-site request forgery (CSRF)​​.

To implement it, we can add what we learned earlier like this:


// This function will try to gain access to third-party cookies
function requestThirdPartyCookieAccess() {
// Check if you already have access to third-party cookies
document.hasStorageAccess().then(hasAccess => {
if (!hasAccess) {
// If you don't have access, request it
document.requestStorageAccess().then(
() => {
console.log("Access to third-party cookies granted");
// Here you can perform operations that require third-party cookies
},
() => {
console.log("Access to third-party cookies denied");
// Handle the situation where access is not granted
}
);
} else {
console.log("You already have access to third-party cookies");
// Continue with normal operations
}
});
}
// Call the function when necessary, for example, when loading an iframe
requestThirdPartyCookieAccess();

Related Websites Sets

Related Websites Sets (RWS, formerly known as First-Party Sets or FPS) allow a company to declare relationships between multiple websites. This is done so that browsers allow limited access to third-party cookies for specific purposes, balancing user privacy expectations with the desired functionality on the websites they interact with​​​​.

The application of RWS is particularly relevant for organisations with multiple domains that wish to share certain cookie information between them for specific functions, while still maintaining user privacy. This is useful for cases like single sign-on (SSO) or persisting user preferences across different domains of the same entity. RWS provides a structured and transparent way to declare these related websites relationships and manage cookie access in an increasingly privacy-focused browsing ecosystem.

Federated Credential Management API

It allows websites to securely interact with third-party authentication systems. It provides a standardised way for users to log into different websites using their existing accounts with identity providers like Google or Facebook, improving the login experience while maintaining security.

This only applies if you are an Identity Provider (the "log in with..." feature), which is unlikely to occur.

Legal Issues

Since I’m not a legal expert nor an analytics specialist, I’m sharing a live discussion by Pablo Moratinos, Nuria Moreno, and Andres Barreto from Products Hackers that is quite interesting and comprehensive.

For example, it is mentioned that currently, it is accepted that companies that are not public can make the option to browse without cookies a paid feature. It is mandatory to include it, but it can also be an additional source of income.

This live session, which is so useful in completing the information in this post, came about because of the bombshell that Pablo Moratinos discovered: the current interpretation of the law does not require asking users for cookie consent if those cookies are for analytics purposes:

Conclusions

We will have to see how it ends up affecting analytics tools, but I foresee calculating users with logs.

If you like this article, you would help me a lot by sharing my content:
Interested in Advanced SEO Training?

I currently offer advanced SEO training in Spanish. Would you like me to create an English version? Let me know!

Tell me you're interested
You might be interested in other articles:
SEO Articles
Usamos cookies para asegurar que te damos la mejor experiencia en nuestra web. Aquí tienes nuestra política de privacidad.