I found a workable solution/workaround to this situation, sortof. It might not work perfectly in your scenario, but I’ll leave it here in case someone else can use it for something.
I have a metafield that contains keywords pertaining to the product. I loop over this list to create a link for each keyword, which is displayed at the bottom of my product description. The link takes the customer to the search results for that word. This is both for the customer and for SEO purposes, basically creating a second set of Tags I can show the user, without exposing all the regular/system Tags I use to do internal stuff like sorting posters based on language, dimensions, orientation, etc.
As an example, see the ‘KEYWORDS’ section in the product description for this alphabet/letter poster in my shop: https://rouxposter.com/products/the-letter-n-a-poster-with-english-n-words
Click on any word in the list, and you’ll see that the search results find at least one poster (I haven’t implemented the keywords on all my posters yet).
As the keywords are in a metafield, they won’t trigger any search results by themselves (sadly). So what I’ve done is I’ve added the keywords to the bottom of my product description, preceded by the word ‘search-split’, e.g.:
(in the product description field)
My product description blah blah blah
search-split my, list, of, keywords, or anything else you want to be searchable but not visible.
In my product-template.liquid, I split the product.description in two by using ‘search-split’ as the splitting text. I then output the first part of the product description, effectively hiding the keywords from the user, while still letting them be part of the searchable words for this product:
(in product-template.liquid, when outputting the product description)
<!-- ROUX HIDE SEARCH KEYWORDS -->
{% assign hide-search = product.description | split: "search-split" %}
{{ hide-search | first }}
This does require you to add the keywords twice in my specific use-case (both in metafield and in product description), which probably isn’t all that clever. While writing this, I realised I don’t really need the metafield, I just need to create my links by looping over the second part of ‘hide-search’. I ended up dropping the metafield completely and just doing this instead:
<!-- ROUX HIDE SEARCH KEYWORDS -->
{% assign hide-search = product.description | split: "search-split" %}
{{ hide-search | first }}
<!-- ROUX MAKE KEYWORD LINK LIST -->
{% if hide-search.size == 2 %}
{% assign keyword-list = hide-search[1]| split: ', ' %}
<h4>Keywords — click to search</h4>
{% for keyword in keyword-list %}
<a href="/search?type=product&options%5Bprefix%5D=none&q={{keyword}}&options%5Bprefix%5D=last" class="keyword-links" title="click here to search for '{{keyword}}'">{{ keyword }}</a>{% if forloop.last != true %},{% endif %}
{% endfor %}</p>
{% endif %}
Of course, you probably don’t need the link list like me, so just skip the second part of the code.
In closing, I’ve basically made a hack for hiding specific text from the product page while keeping the hidden text searchable, which is probably not useable in most metafield-related cases. I hope someone can still use this for something. Let me know what you think.