Free scan About Support Contact
Get Velo

Already have an account? Log in

How to add a cookie banner to WordPress without a plugin

Cookie banners 24 September 2026· 6 min read
The Velo mascot presents a consent banner card and a giant cookie

All posts

To add a cookie banner to WordPress without a plugin, paste your consent tool's script into the site head from a child theme: a short function in its functions.php, hooked to wp_head at priority 1. That prints it ahead of the scripts WordPress queues and keeps it through theme updates. Never paste it into the parent theme's header.php, because the next update deletes it.

What does "without a plugin" really mean?

People mean one of two things. Some want to avoid a consent plugin that adds its own settings screens, database tables and update cycle. Others want no plugin at all, not even a small tool for pasting code into the header. Both are possible, and the method below meets the stricter version.

What you cannot skip is the consent tool itself. A banner built from HTML and CSS alone shows a notice. Unless it also stores the choice, holds back scripts until the visitor decides, and sets the consent state Google's tags read, it collects nothing your tags can act on. That work is what a consent management platform does, and on WordPress the lightest way to add one is a single hosted script in the head.

Our own WordPress install guide uses a header snippet tool, because it is the quickest route for most sites. The child theme route does the same job with nothing extra installed.

Where should the script go in WordPress?

There are four places people put it. Only two of them last.

  • The parent theme's header.php. The route most tutorials give, through Appearance and the theme file editor. It works until the theme updates, then the file is replaced and the banner is gone.
  • A child theme's functions.php. Survives parent theme updates and lets you choose where in the head the script prints. This is the one we recommend.
  • A header code field in the theme's settings. Some themes offer one. It survives updates, but not a switch to another theme, and you cannot control its order against other head scripts.
  • A block theme's template. Block themes have no header.php, and the site editor's header is page content, not the document head. Use the child theme hook here too.
WHAT WP_HEAD PRINTS, IN ORDER priority 1 · your consent script sets the default consent state first priority 9 · queued scripts a plugin that queues its Google tag prints here priority 10 · everything hooked by default snippets added without a priority land here Lower numbers print earlier in the page head. PARENT HEADER.PHP script pasted by hand gone after a theme update no warning, banner simply missing CHILD THEME functions.php hook kept through updates parent updates leave it alone
How WordPress orders the head, and where the script survives. A consent script hooked at priority 1 prints before the queued scripts at priority 9, which is where a plugin that queues its Google tag has it printed. Pasted into the parent theme instead, the same line disappears at the next update.

How do you add it with a child theme?

Six steps. Budget half an hour the first time, most of it on the check at the end.

  1. Copy the full script from your consent tool

    Take the installation snippet from your consent tool's dashboard exactly as it is given, including any site ID and data attributes. Retyping it is how attributes go missing.

  2. Create and activate a child theme

    A child theme is a small folder with a style.css that names your current theme as its parent, plus its own functions.php. WordPress loads it on top of the parent, and parent theme updates leave it alone. Activate it before you add anything.

  3. Print the script in wp_head at priority 1

    In the child theme's functions.php, add a function that echoes the script tag and hook it with add_action on wp_head at priority 1. WordPress prints the scripts it has queued at priority 9, so priority 1 places the consent script ahead of them.

  4. Remove the old banner and exclude the script from optimisation

    Deactivate any consent plugin you used before, so only one tool sets Consent Mode defaults. If a caching or performance plugin combines, defers or delays JavaScript, add the consent script to its exclusion list.

  5. Clear every cache

    Purge the page cache, any server cache and the CDN. A cached page keeps serving the head it had before your edit, so the banner seems not to work when it has not reached the page yet.

  6. Check the live page before and after a choice

    Open the site in a private window from a region where consent is required. In the page source, the consent script should come before any gtag.js or googletagmanager.com request. In the network panel, filter for collect: before a choice there is no request in basic mode, or one carrying gcs=G100 in advanced mode. Accept all and the next request should carry gcs=G111. The full checklist is in how to test a cookie banner before going live.

Why does the load order matter?

Google's tags read the consent state at the moment they run. Google's Consent Mode setup guide asks for the default state to be set before any command that sends measurement data. If the Google tag prints first, its first request can leave before any default exists, and in regions that require consent that request is sent as if nobody had asked.

On WordPress the Google tag often arrives through a plugin, and a plugin that queues its script has it printed with the others at priority 9. A consent script hooked at the default priority 10, which is what you get when you leave the number out, prints after it. That single missing argument is a common reason a correctly configured banner still shows tags firing before consent. Some plugins print their own tag at priority 1 as well; if the page source shows one ahead of the consent script, use a lower number such as 0. Two more things can move the order after you have set it: a theme that writes a script straight into header.php above wp_head(), and an optimisation plugin that delays scripts until the visitor interacts. The page source check in step 6 catches all three.

If your measurement tags run through Google Tag Manager instead, the order is set inside the container. Add the consent tool as a tag on the Consent Initialization trigger, as the Tag Manager route on our WordPress guide shows, and keep the container snippet itself in the head as before.

How Velo handles it

Velo on WordPress is one script line, with no consent plugin to install or update. The script sets Consent Mode defaults to denied for regions that require consent as soon as it runs, so the child theme hook above is the right placement. Check the order on the live page as in step 6, since other plugins can still print ahead of it.

Common questions

What people ask about this topic.

How do I add a cookie banner to WordPress without a plugin?

Use a hosted consent tool and print its script in the site head from a child theme: add a function to the child theme's functions.php that outputs the script tag, hooked to wp_head at priority 1. That runs it before the scripts WordPress queues and survives parent theme updates. Then clear caches and check the page.

Will a theme update remove my cookie banner code?

Yes, if the code sits in the parent theme's header.php or functions.php. Updating the theme replaces its files and the script disappears without a warning. Code in a child theme survives parent theme updates, and a header code field in the theme's own settings survives them too, though not a switch to a different theme.

Can I code my own cookie banner in WordPress?

You can build the notice, but a banner is only useful if the choice changes what runs. It has to store the choice, hold back scripts until consent where the law requires it, set Consent Mode defaults and updates for Google's tags, and keep a record of consent. That is most of what a consent tool does, so most sites load one.

Does the cookie banner script need to load before Google Analytics?

Yes. Google's tags need a default consent state before they send anything, so the consent script has to run before the Google tag. In WordPress, print it at priority 1 of wp_head, above anything the theme or plugins queue, and check the order in the page source on the live site.