We're showing the results of a text search across several posts, and we want to have the search terms highlighted in the resulting page. Right now, we're doing this on the backend, going through the post text and title, wrapping any occurrences of the search term in a <strong class="highlighted">
tag. This is happening in PHP, like so:
foreach($terms as $t) {
$t_text = preg_replace('/\W/u','',$t);
$re = "@\b$t_text\b@ui";
if( !in_array($t_text, ['a','em','strong','span','div','blockquote','font'])) {
if(strlen($t_text) > 1) {
$row['text'] = preg_replace($re,'<strong class="highlight">$0</strong>',$row['text'] );
$row['title'] = preg_replace($re,'<strong class="highlight">$0</strong>',$row['title'] );
}
}
}
(Where $terms
is the list of search terms, and $row
is a post which contains the search terms)
We have noticed that, when the search term is included in a tag's attribute (i.e. say we're searching for "foo", and we have a link like this: <a href="foo.php">Some text including foo</a>
), the term in the attribute is also wrapped, breaking the attribute, and we end up with horribly mangled markup. Is there some way to do this with JS, rather than making the regex we're using on the backend much more complicated? (I'm open to a jQuery solution).
I have already tried various methods, including the :contains
selector, filtering out everything but leaf nodes (this doesn't work because the a
tag may have tags inside of it), filtering out everything but text nodes (doesn't work because attribute text is included here too).
In case this isn't totally clear, here's an example of the markup for the body of a hypothetical post (we store these directly in a database), where the search term is "post":
<p>
Here is <a href="post.php?id=42"><em>another</em> post</a> that is relevant to this one.
</p>
After running the above PHP code on the post, it looks like this:
<p>
Here is <a href="<strong class="highlight....
... and the whole thing is broken.
... Update
To those requesting relevant code: I don't know how to solve this problem, so there is not any code to include yet. I am asking what the code to solve this problem should look like. If there is something about the question that is unclear, please point it out and I will gladly expand.