Search by

bensomething / craft-namecheck

bensomething

Automatically link the names of your entries wherever your content mentions them.

Package info

github.com/bensomething/craft-namecheck

Type:craft-plugin

pkg:composer/bensomething/craft-namecheck

Statistics

Installs: 6

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.0-beta.4 2026-11-06 13:58 UTC

This package is auto-updated.

Last update: 2026-11-06 14:05:11 UTC


README

Namecheck

Namecheck

Link the names of your entries wherever your content mentions them.

Write "Pulp headline the Saturday" in a news story and Namecheck links "Pulp" to your Pulp page as it's rendered. Your content is never rewritten, links are added on the way out. Old articles pick up links to pages you add later, and nothing needs tidying if a page goes away.

Note

Namecheck is in beta. It's feature-complete and safe to try, but its API and settings may still change before 1.0.0. Please report anything you hit.

Requirements

  • Craft CMS 5.10 or later
  • PHP 8.2 or later

Installation

composer require bensomething/craft-namecheck:^1.0.0-beta
php craft plugin/install namecheck

Setup

In Settings → Plugins → Namecheck:

  • Link To: the sections whose entries get linked, such as Performers.
  • Track Mentions In: the sections whose entries are checked for mentions when they're saved, such as News. Optional: only needed for craft.namecheck.mentionedIn().
  • Link First Mention Only: link each entry once per piece of content (on by default).
  • Match Case: match names only as they're capitalised (on by default, and recommended).

Linking Mentions

Run any HTML through the namecheck filter, passing the entry it belongs to:

{{ entry.body|namecheck(entry) }}

The text is searched for entry titles as whole words, so "Air" is found in "Air played" but not in "Airline". Longer names win, so "Pulp Fiction" is linked rather than "Pulp" inside it. An entry is never linked to itself, and existing links, headings, captions, code and form controls are left alone.

For text that doesn't belong to an entry, such as a footer in a global set, leave the entry out: {{ footer.text|namecheck }}. Names are then linked for the current site, but entries set to Only where it's related never are, since there's no entry to check their relations against. To give options without an entry, pass null in its place: |namecheck(null, { limit: 3 }).

The filter takes options as a third argument:

{{ entry.body|namecheck(entry, {
    firstOnly: false,
    limit: 5,
    attributes: { class: 'mention' },
    exclude: [entry.festival.one()],
}) }}
Option
firstOnly Overrides the Link First Mention Only setting.
limit The most entries to link to.
attributes Extra attributes for each link.
exclude Entries (or IDs) not to link.

Content rendered in pieces counts as one piece when each call is passed the same entry. That covers a CKEditor field rendered chunk by chunk, or a body and a sidebar: an entry linked in one call isn't linked again by the next, and limit counts across them all.

{% for chunk in entry.body %}
    {{ chunk.type == 'markup' ? chunk|namecheck(entry) : chunk }}
{% endfor %}

Links can also be given attributes everywhere through the linkAttributes setting in config/namecheck.php.

Linked HTML is cached until the content or a linked entry changes, or for Craft's cacheDuration at most. So a pending entry is linked once it goes live, though possibly not until that cache next expires.

Names That Are Also Words

Some names are everyday words: Air, Wednesday, Boston, Sparks. For these, add a Namecheck field to the entry types you link to. It gives each entry two settings:

  • Link This Entry:
    • Wherever it's mentioned (the default).
    • Only where it's related: linked only in content that relates the entry, for example through an entries field on the article. Pass the article to the filter for this to work.
    • Never.
  • Other Names: anything else the entry is known as, one per line, such as "Beatles" for "The Beatles". These are matched as well as the title.

Entries without the field are linked wherever they're mentioned. Curly and straight apostrophes match each other, as do ordinary and non-breaking spaces. A name shared by two entries is ambiguous, so it isn't linked to either. Disabled and pending entries count, and the Namecheck field warns about any names its entry shares.

Mentions

With Track Mentions In set, each entry in those sections is checked for mentions when it's saved, by its title and the text of its fields. Relation fields don't count: picking an entry isn't mentioning it. List mentions from either side:

{# On a performer's page: news that mentions them #}
{% set news = craft.namecheck.mentionedIn(entry).section('news').orderBy('postDate desc').limit(6).all() %}

{# On an article: the entries it mentions #}
{% set mentioned = craft.namecheck.mentionedBy(entry).all() %}

Both return an entry query, so narrow and order them like any other.

In the control panel, a linked entry's sidebar lists the entries that mention it under Mentioned In, with the fields they mention it in. Entry indexes can also show a sortable Mentioned In column with how many entries mention each one, which is handy for finding the entries nothing mentions.

When a linked entry is added or renamed, or its other names change, mentions are updated in the queue. Changing the plugin's settings does the same, whether in the control panel or through project config. To rebuild them by hand:

php craft namecheck/mentions/rebuild

Entries nested in Matrix or CKEditor fields count too, at any depth, whether or not their fields are searchable.

Finding Entries by Name

For lists where every item is a whole name, such as a line-up typed as text, look the names up instead of linking them. A name matches an entry's title or one of its other names, ignoring case, but only in full: "Neil Young and the Chrome Hearts" won't find Neil Young.

{% set names = entry.lineupText|split(',')|map(name => name|trim) %}
{% set found = craft.namecheck.findAll(names) %}

{% for name in names %}
    {% set performer = found[name] ?? null %}
    {{ performer ? tag('a', { href: performer.url, text: name }) : name }}
{% endfor %}

craft.namecheck.find('Jesus and Mary Chain') looks up a single name. Entries set to Never aren't found. Only where it's related doesn't apply here, since a name in a list is never an everyday word.

Caches

Names and links are cached until a linked entry is saved or deleted. Clear them by hand under Utilities → Caches → Namecheck names and links, or with php craft clear-caches/namecheck.

Configuration

Every setting can be set in config/namecheck.php:

<?php

return [
    'targetSections' => ['performers'],
    'sourceSections' => ['news'],
    'firstOnly' => true,
    'caseSensitive' => true,
    'linkAttributes' => ['class' => 'mention'],
    // Elements whose text is never linked.
    'skipTags' => ['a', 'button', 'code', 'figcaption', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'kbd', 'label', 'option', 'pre', 'script', 'select', 'style', 'textarea'],
];