How to Add a Script to the <head> of a WooCommerce Store (Without Breaking Your Theme)
Analytics, heatmap and pop-up tools usually ask you to paste a snippet into the <head>of every page. On a WooCommerce store, the tempting shortcut is to open your theme's header file and paste it in. That works until the next theme update quietly erases it, or until a typo takes the whole site down. This guide shows the approach WordPress's own developer documentation points to: the wp_head hook, placed in a tiny plugin or a child theme, so your snippet survives updates and works with both classic and block themes.
Updated

How WordPress builds the <head> (and why that matters)
WooCommerce runs on WordPress, so its pages (shop, product, cart, checkout and the rest) are WordPress pages, rendered by your active theme. WordPress doesn't expect you to hand-edit the head of each page. Instead, it offers a hook.
The WordPress developer reference describes wp_head as an action that "prints scripts or data in the head tag on the front end." It is triggered inside the <head></head> section by the wp_head() function. WordPress core itself hooks many default functions to it, and the reference calls it one of the most essential theme hooks, widely supported by themes.
That gives you a clean way in: write a few lines of PHP that say "when WordPress prints the head, also print my snippet." The snippet then appears on every page that uses the theme's normal head, with no template files touched.
This works for both kinds of WordPress themes:
| Theme type | Where the <head> comes from | What that means for you |
|---|---|---|
| Classic theme (PHP templates) | The theme's header.php, which calls wp_head(). | You could edit header.php, but the hook is safer. |
| Block theme (templates built from blocks) | WordPress core. When a block template is used, WordPress renders it through its own template-canvas.php file and adds its own output to wp_head. | There is no theme header file to paste into. The hook is the natural way to add head code. |
<script src="https://...your tag..."></script>. Always paste the exact snippet your tool gives you. In marketingLABO, for example, you register your site with its name and URL, and the dashboard shows your tracking tag with a Copy tag button and the instruction to paste it right before </head> on every page.What not to do: edit the parent theme
The most common way people break a WooCommerce store while adding a script is editing the active theme's files directly, often through Appearance > Theme File Editor. The official documentation is blunt about the risks:
- Updates erase your changes. WordPress's Theme File Editor documentation says that if you update the theme, all of your changes will be lost, and points to child themes as the way to avoid that. WooCommerce's customization guide gives the same warning: modifications are lost when theme files are overwritten during an update.
- No backups. The same WordPress page notes that the editor does not make backup copies.
- One mistake can lock you out. If you introduce an error that crashes your site, WordPress says you cannot use the editor to fix the problem; you have to use FTP to upload a working file or rename the theme folder.
In other words, the problem isn't the script; it's where you put it. Keep your code outside the parent theme and both problems go away.
Your three safe options at a glance
| Option | Survives theme updates? | Survives switching themes? | Best for |
|---|---|---|---|
| A. A tiny custom plugin using wp_head | Yes | Yes | Most stores. Site-wide code that has nothing to do with design. |
| B. A child theme's functions.php using wp_head | Yes | No | Stores that already use a child theme for other customizations. |
| C. A code snippets plugin | Yes | Yes | Owners who prefer adding PHP from the admin screen. WooCommerce's own customization guide recommends the Code Snippets plugin for PHP changes instead of pasting into functions.php. |
WordPress's theme handbook explains why option A is often the better fit: functions.php behaves like a plugin, but only the active theme's file runs, so its features are lost when you switch themes. For functionality that should work regardless of how the site looks, the handbook says it is best practice to put it in a plugin. A tracking tag is exactly that kind of code: you want it to keep working after a redesign.
Before you start
- Back up the site. WooCommerce's child-theme guide starts with this step for a reason. Use your host's backup tool or whatever backup system you already have.
- Get file access outside WordPress. Make sure you can reach your files through your host's file manager or SFTP. If a PHP typo ever causes an error, that is how you undo it.
- Copy the snippet from your tool. Don't retype it. Note whether it is a single
<script>line or a longer block; both work with the methods below. - Use a staging copy if your host provides one. Not required for a change this small, but it's a good habit before touching PHP on a live store.
Option A: Add the script with a tiny plugin (recommended)
WordPress's plugin handbook describes a plugin, at minimum, as a PHP file with a plugin header comment that contains the plugin's name. Plugins live in wp-content/plugins, ideally in their own folder. That is all you need.
Create a file named site-tracking-tag.php with this content, replacing the placeholder line with your real snippet:
<?php
/**
* Plugin Name: Site Tracking Tag
* Description: Prints the tracking tag in the <head> of every front-end page.
*/
// Stop the file from being loaded outside WordPress.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
add_action( 'wp_head', function () {
?>
<!-- Tracking tag: added 2026-10-12 -->
<script src="https://...your tag..."></script>
<?php
}, 99 );How the pieces work:
- The header comment is what makes WordPress recognize the file as a plugin. "Plugin Name" is the only required line.
- The ABSPATH check is a common safety habit: if someone requests the file directly, it does nothing.
add_action( 'wp_head', ... )tells WordPress to run your function when it prints the head.- The
?>...<?phppair switches out of PHP so your snippet is printed exactly as pasted. You don't need to escape quotes inside it. - The
99is the hook priority. Functions with lower numbers run first (the default is 10), so a high number prints your snippet late in the head, close to</head>, which is where many tools ask for it.
Now install it:
- Using your host's file manager or SFTP, create the folder
wp-content/plugins/site-tracking-tag/and uploadsite-tracking-tag.phpinto it. Alternatively, zip the folder and upload it from Plugins > Add New Plugin > Upload Plugin. - In the WordPress admin, open Plugins. You should see "Site Tracking Tag" in the list.
- Click Activate.
- Check that it works (see "Test it" below).
To remove the tag later, deactivate the plugin. To change it, edit the one line inside the file. Your theme is never touched, so theme updates and redesigns don't affect it.
Option B: Add it to a child theme
If your store already runs on a child theme, you can put the same code in the child theme's functions.php. WordPress's child theme documentation explains why this is safe: a child theme keeps your modifications separate from the parent, so you can still receive parent updates without losing them. The child's functions.php doesn't replace the parent's; both are loaded, with the child's loaded immediately before the parent's.
If you don't have a child theme yet, the minimum is small. Per WordPress's documentation, only style.css is required, and its header needs a Template field whose value exactly matches the parent theme's folder name:
/*
Theme Name: My Store Child
Template: parent-theme-folder-name
*/- Create a folder in
wp-content/themes/(for examplemy-store-child) containing thatstyle.css. - Add a
functions.phpfile to the same folder with theadd_action( 'wp_head', ... )block from Option A (everything fromadd_actiondown, after an opening<?phpline). Don't copy the parent theme's functions into it; WordPress warns that duplicate function names cause fatal errors. - Upload the folder, or zip it and upload it under Appearance > Themes > Add New.
- Go to Appearance > Themes and click Activate on the child theme.
A few caveats specific to WooCommerce stores:
- Classic vs. block themes. WooCommerce's child-theme guide covers classic child themes and points to separate resources for block child themes. WordPress's child theme documentation covers both; for block themes it notes that styling is generally handled through theme.json, so loading the child's style.css is often unnecessary.
- Premium child themes. WooCommerce advises against adding custom code to a premium child theme, because updates to that theme overwrite it. If your theme vendor ships its own child theme, use Option A instead.
Option C: A code snippets plugin
WooCommerce's "Customizing WooCommerce: best practices" page recommends the Code Snippets plugin for PHP changes, so you don't have to paste code into functions.php. If you prefer working from the admin screen, you can add the same add_action( 'wp_head', ... ) code there. Follow that plugin's own instructions for creating and activating a snippet, and keep the snippet limited to front-end output.
What about copying header.php into a child theme?
On a classic theme there is one more route you will see in tutorials. WooCommerce's child-theme guide explains that you can copy a parent template, such as header.php, into the child theme folder and edit the copy; the child's version is then used in place of the parent's. You could paste your snippet above </head> in that copy.
It works, but it is the least robust of the options for a tracking tag, for three reasons:
- You freeze a copy of the header. When the parent theme improves or fixes its header.php in an update, your child copy keeps the old version until you merge the changes by hand.
- It only exists on classic themes. Block themes don't have a header.php to copy.
- It solves a bigger problem than you have. Overriding a whole template is meant for changing layout or markup. Adding one snippet to the head is exactly what the wp_head hook is for.
If your child theme already overrides header.php for design reasons, the hook-based code from Option A still works alongside it, as long as the copy keeps its wp_head() call. Leave that call in place.
Managing several tools in one place
Stores rarely stop at one tag. An analytics tool, an ad platform and a pop-up tool might each ask for a snippet in the head. Keeping them together in the same small plugin makes them easy to audit:
- One labeled block per tool. Put each snippet in the same
wp_headfunction, each with an HTML comment naming the tool and the date you added it. - Remove what you no longer use. Every snippet is extra work for the browser. When you cancel a tool, delete its block the same day.
- Keep a record outside the code. A short list of which tools are installed, where and why helps the next person who works on the site, and helps you spot duplicates.
If a tool asks for code in a different place, such as just after the opening <body> tag, follow its instructions; that is a different hook. This guide covers the head only.
Why not wp_enqueue_script?
If you have read WordPress development guides, you may have seen wp_enqueue_script(). The developer reference calls it "the recommended method of linking JavaScript to a WordPress generated page," called from the wp_enqueue_scripts hook. Since WordPress 6.3 it also accepts an $args array with in_footer (default false) and a strategy of defer or async.
That function is the right tool for scripts you build and ship yourself. For a vendor's tracking snippet, the priority is usually different: paste exactly what the vendor gave you, in the place they asked for. Re-creating a snippet with wp_enqueue_script can change details such as attributes, load order or inline parts, and if the tool's instructions say "paste right before </head>," printing the snippet verbatim through wp_head is the most faithful way to follow them. If your vendor publishes official WordPress instructions, follow those.
Test it
- Clear caches. If you use a caching plugin or your host caches pages, clear it so you see fresh HTML.
- Open the store in a private window and view the page source (Ctrl+U on Windows, Option+Cmd+U in Chrome on Mac).
- Search for part of your snippet, such as its domain. It should appear inside the head, near
</head>. - Repeat on WooCommerce pages: the shop page, a product page, the cart and the checkout page.
- Use your tool's check. In marketingLABO, open any page of your store, then press Check tracking in the dashboard. If nothing arrives, the dashboard suggests confirming the tag is right before </head> on every page and that your changes are saved, then reloading the site and trying again.
Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| The site shows a critical error after uploading the file | A PHP syntax mistake (often a missing semicolon or bracket). | Use SFTP or the file manager to rename or delete the plugin folder (or revert functions.php). The site comes back; fix the file and try again. |
| The snippet isn't in the page source | Plugin not activated, child theme not active, or an old cached page. | Check Plugins or Appearance > Themes, then clear caches. |
| The snippet appears twice | The tool was also added another way (an old header.php edit, another plugin, a snippets plugin). | Keep exactly one installation, or page views may be counted twice. |
| It worked, then stopped after a redesign | The code lived in functions.php of a theme you switched away from. | Move it to a plugin (Option A). |
| It shows on most pages but not one | That page uses a template that doesn't output the normal head (for example, some landing-page builders). | Check that page's template, or ask its plugin vendor how to add head code. |
WooCommerce pages your tag covers, including the thank-you page
Unlike some hosted platforms, a WooCommerce checkout is a page on your own WordPress site. WooCommerce's developer documentation describes endpoints as "an extra part in the website URL" that shows different content when present; the order received (thank-you) page, for example, is the checkout page with order-received/ added. You can review or change endpoint slugs under WooCommerce > Settings > Advanced.
Because the theme renders these pages, a wp_head snippet loads on them too. The exception is any step your payment provider hosts on its own website; those pages aren't yours, so no tag of yours runs there.
This is useful for page-based goals. With marketingLABO, for example:
- A thank-you page goal. Micro-conversions can be set by specific URL, so reaching the order received page can be counted. (marketingLABO doesn't read order values or products; it sees which pages were viewed.)
- A cart reminder by page behavior. Pop-up banners can target visitors who have viewed some pages and not others, for example people who viewed
/cart/but not the order received page, and can be triggered after a delay, at a scroll depth or on exit intent. - Product page heatmaps. See scroll depth and clicks on the pages shoppers read before adding to cart.
For orders and revenue, keep using WooCommerce's own reports. marketingLABO has no WooCommerce plugin or store-data integration; it works from the page tag alone. If you also run a Shopify store, the method there is different. See our guide to adding a tracking script to Shopify's theme.liquid.
Quick checklist
- Site backed up, and you can reach files over SFTP or the host's file manager.
- Snippet copied directly from your tool.
- Added through wp_head in a small plugin (or a child theme, or a code snippets plugin), not in the parent theme.
- Plugin or child theme activated.
- Caches cleared; snippet found in the page source on shop, product, cart and checkout pages.
- Installed only once.
- Tool's own tracking check passed.
FAQ
Will a WooCommerce or theme update remove the script? Not if it lives in its own plugin or in a child theme. That is the point of keeping it out of the parent theme.
My theme is a block theme with no header.php. Can I still do this? Yes. With block templates, WordPress builds the page through its own template-canvas.php file and still fires wp_head, so Options A and C work unchanged, and Option B works with a block child theme.
Does the script run in the WordPress admin? No. wp_head prints to the head on the front end, so it doesn't appear on wp-admin screens.
Where does the Shopify version of this live? See How to add a tracking script to your Shopify store.
marketingLABO's Free plan includes one site with analytics, heatmaps and visitor history, plus one form and one pop-up banner, with no credit card required. Compare plans on the pricing section, or sign up free to get your tag.
Sources
All checked on October 12, 2026.
- WordPress Developer Reference: wp_head hook
- WordPress Developer Reference: locate_block_template() (template-canvas.php)
- WordPress Theme Handbook: Child themes
- WordPress Theme Handbook: Theme functions (functions.php)
- WordPress Plugin Handbook: Plugin basics
- WordPress Developer Reference: wp_enqueue_script()
- WordPress Documentation: Appearance Theme File Editor screen
- WooCommerce Developer Docs: How to set up and use a child theme
- WooCommerce: Customizing WooCommerce best practices
- WooCommerce Developer Docs: Understanding WooCommerce endpoints
Start free — no credit card needed
Sign up freeMore articles

Website Heatmaps Explained: Click, Scroll and Mouse-Movement Maps for Small Sites
What click, scroll and mouse-movement heatmaps show, how to read scroll depth on product pages, and the common misreads that lead small sites to the wrong fix.
Read the article →
Cart Abandonment: Why Shoppers Leave and What You Can Do On-Site
Why shoppers abandon carts, based on Baymard Institute research, and the on-site fixes and returning-visitor reminders that address each reason.
Read the article →
How to Build a Welcome Email Series for a Small E-commerce Store
A step-by-step plan for a 4-email welcome series: timing, wait steps, branches on opens and return visits, sample copy, and the CAN-SPAM basics.
Read the article →
Free Shipping Banners: Where to Show Them and How to Word the Threshold
Where to place a free shipping banner (bar or modal), when to show it, and how to word the threshold so it matches your checkout.
Read the article →
Form Abandonment: How to Find the Field Where People Give Up
How to measure form abandonment field by field, read a drop-off report, and decide what to fix first: field count, order, labels or validation.
Read the article →
How to Target Returning Visitors with Different Messages Than First-Timers
Show first-time and returning visitors different messages using visit frequency and days since the last visit, with recipes and the limits of tracking.
Read the article →