This article comes with a free Claude skill
The rule this story ends with is packaged as wp-inline-js-safety – one small file you drop into Claude Code so your own assistant works this way too. It is public domain: copy it, change it, no attribution and no permission needed. How to install it is at the end of this article.
The page looked perfect. One button just did nothing.
We have a page on this site that helps you work out whether a food is safe for a rat. It is mostly JavaScript: you pick a food, it does some arithmetic, it tells you the answer.
One day it stopped answering. Not with an error. Not with a blank page. The page rendered exactly as it always had, every word in place, and the button simply did not respond. Nothing in the server logs. Nothing in the PHP error log. The code had not changed.
The cause turned out to be WordPress, and it is worth writing down because it is the kind of thing you cannot reason your way to. You have to already know.
Why WordPress turns && into an HTML entity inside a script tag
WordPress runs page content through a tidying filter that makes typography look nicer: straight quotes become curly ones, three dots become an ellipsis. Useful for prose.
It also encodes an ampersand that it finds sitting between a less-than sign and a greater-than sign, because in that position it looks like it belongs to an HTML tag.
Now consider ordinary JavaScript:
if (weight < limit && age > minimum) { ... }
What arrives in the browser is this, and if you have landed here from a search for those characters, this is the thing you pasted:
if (weight < limit && age > minimum) { ... }
Read that as the filter reads it, with no idea it is code. There is a <. Later there is a >. Between them sits &&. So the ampersands get converted into HTML entities, and what reaches the browser is not JavaScript any more. It is a syntax error.
The entire script block dies. Not the one line. The browser hits the broken statement, abandons the whole block, and every function defined in it is silently absent. Your page looks completely normal and nothing in it works.
Nothing on the server ever knew. From PHP’s point of view the page was generated correctly, because it was: the damage happens after your code has finished, on the way out.
How to avoid it
Three habits, in order of how much they help:
- Do not let
&&sit between a<and a>. Flip the comparison so the angle brackets point the same way:if (limit > weight && age > minimum). Same logic, nothing for the filter to catch. - Put page behaviour in a properly enqueued script file, not inline in page content. Files are not passed through the content filter at all. This is the real fix; the first habit is for when you genuinely must emit inline code.
- If you must emit inline JavaScript, emit it somewhere the filter does not reach. In our case that meant hooking the footer rather than putting it in the page body.
The part that cost us the most
We did not find this by reading the code. We had read the code several times, and the code was correct.
We found it by looking at what the browser actually received, which was different from what we had written. That gap is the whole lesson, and it is why we now have an automated check that compares emitted JavaScript against what WordPress’s own filter does to it, using the real filter rather than our idea of it.
If a page of yours is behaving impossibly, view the source the browser got. Not your template. Not your file. The bytes that arrived.
We wrote this up as a skill
Everything above is generic: it is true of any WordPress site, and none of it is about rats.
So it exists separately as a short instruction file for AI coding assistants, along with ten others we extracted from the same project. Each one is a habit that exists because something here went wrong first. They are public domain, free to copy, and require nothing from us:
https://github.com/blonderoofrat/agent-skills
They are deliberately unmaintained snapshots rather than a project. If one is wrong for your situation, change it. That is easier than asking us to.
Get the skill
Everything above is generic. None of it is about rats, and none of it is specific to this site. So the rule is also published on its own as a Claude skill: a single Markdown file that an AI coding assistant reads and applies when the situation comes up.
The file: wp-inline-js-safety/SKILL.md
Or take the whole set:
git clone https://github.com/blonderoofrat/agent-skills
Installing it in Claude Code. Copy the skill’s folder into one of these, so the file ends up at .../skills/wp-inline-js-safety/SKILL.md:
~/.claude/skills/(available in every project on your machine)your-project/.claude/skills/(that one project only)
Claude reads it at the start of the next session and applies it when what you are doing matches the description at the top of the file. You can also ask for it by name.
Using a different assistant? The file is plain Markdown with a two-line header. Paste the body into whatever system prompt, rules file or instructions file your tool uses. Nothing in the rule itself is Claude-specific.
Licence: CC0, public domain. Copy it, adapt it, ship it in commercial work, no attribution required. These are deliberately frozen snapshots rather than a maintained project, so if one is wrong for your situation, change it. That is easier than asking us to.
Part of Notes from building this site: articles about working practices that exist because something here went wrong first. The rule above is also published on its own, as a free public-domain instruction file for AI coding assistants — the wp-inline-js-safety skill, in blonderoofrat/agent-skills on GitHub.
Filed under News about this site




