Guide 11 · Developer docs

Search, filtering and faceted navigation

Site search on Core dna is an Elasticsearch index that the platform fills and queries, and a page you build. What reaches the index, search views, the search page, product facets, filtered listings that need no index, and when to go beyond the built-in index.

L2
Unit 01 · Indexing and search views

What the index holds

Site search finds only what was put into the index. Which record types are indexed, the conditions each record has to meet, what a search document holds, and why the words in your layout areas are not searchable until you map them.

Who this is for. Theme developers and content modellers who need to know what a search can find before they build the page or the model. Afterwards you can say which records a search will return, which of their words it matches, and why a record you expected is missing.

Indexing is opt-in

The words in a record's layout areas are not searchable until each area is mapped to a search field. A page built from twenty components, with every word in an area, is found only by what the platform puts into the index on its own:

  • its name and its URL path;
  • the names and slugs of its tags and categories;
  • its author's display name, where the record has an author;
  • for a blog and a blog post only, their own text: the blog's text and the post's body, with HTML removed.

Everything else, from the hero copy to an FAQ answer to a product's description, reaches the index only through a mapped area. So the usual assumption, that a new site's search finds everything, is wrong: until someone maps the areas, it finds titles. The same goes for a layout added later, whose areas are unsearchable until they are mapped. Mapping is on Search fields.

What gets indexed

The site search index takes pages, blogs, blog posts, FAQ questions and product descriptions. Books, units and book pages joined the list after release 2026.8.1, so a site on that release or an earlier one does not index them. Custom entity records, FAQ pages (their questions are indexed), forms, people, files and products themselves (their descriptions are indexed) are never in site search. Product descriptions also go into a second index, the facets index, which serves product finders (Facets and the mapping template).

A record of those types is indexed only while all three of these hold, and its document is removed as soon as one stops holding:

  • It is published, and its published date has passed.
  • Its SEO Robots settings allow indexing. Don't index, but follow and Don't index and don't follow take the record out of site search as well as out of search engines.
  • A signed-out visitor may read it. The indexer runs in the background with no one signed in, so it loads each record with the public's read privileges. A record restricted to a group is removed, and so is every record of a module whose default read privilege does not include the public.

Each record is in one language, so a translated page is a second document. A filter on language.locale (en-au) selects one language; language.code (en) matches every regional variant of it at once.

Members-only content is never in site search

Because the indexer reads as a signed-out visitor, a record that only members can open is not in the index, not even for members who are signed in. A search over members-only content is built from $_query lookups in the template, which apply the signed-in member's permissions (When a listing should become a search view).

What a search document holds

Each record becomes one document. Ask a view for one record, by its type and id, and you see the document as the index holds it. This one is a how-to on this site, a blog post:

A blog post's search document
GET /cdna-api/search/hub-docs-search?entityClass=Blogs\Entities\Post&id=117 HTTP/1.1
Host: hub.coredna.com
Authorization: Bearer YOUR_ACCESS_TOKEN
Accept: application/json
Response 200 OK
{
  "result": "success",
  "data": {
    "response": {
      "totalCount": 1,
      "resultItems": [
        {
          "_id": "blogs.entities.post.117",
          "_score": 0,
          "highlight": null,
          "entityClass": "Blogs\\Entities\\Post",
          "id": 117,
          "name": "Set up a base template and extend it",
          "fullPath": "/how-to/base-template-and-extend",
          "nativeText": "One base template holds the document, the head, the chrome and the script queue, and defines blocks. Every page-type template extends it and fills the blocks. Both engines do this the same way.",
          "layoutId": 82,
          "language": {"code": "en", "locale": "en-us"},
          "author": {"displayName": "bwired team"},
          "created": "2026-10-15T09:10:02+00:00",
          "published": "2026-09-30T00:00:00+00:00",
          "indexed": "2026-10-16T00:38:20+00:00",
          "categories": {
            "name": ["Templates in both engines"],
            "slug": ["templates-in-both-engines"]
          },
          "componentLayoutIds": [77, 40, 34],
          "fields": {
            "testing body": ["The page template fills the blocks and adds to one:"]
          }
        }
      ],
      "facets": {}
    }
  }
}
Real response from this documentation site
FieldHoldsMatched by a query's words
entityClass, idThe record type, such as Pages\Entities\Page, and its identityClass only
name, fullPathThe title, and the URL path to link toYes
nativeTextA blog's text or a post's body, HTML removed; absent on other typesYes
language.code, language.localeFor example en and en-usNo
author.displayNameWhere the record has an authorYes
tags.name, tags.slug, categories.name, categories.slugEvery tag and category, as listsYes
created, published, indexedDates in UTC; indexed is when the document was last writtenNo
layoutId, componentLayoutIdsThe record's layout, and every component layout used inside itNo
relatedRecordsThe ids of the records chosen in record and records areas, by typeNo
fields.<name>Your search fields, filled from mapped areas, each as a list. This site's field is called testing bodyText fields only

A missing key means the record has no value for it, as with the tags above. Three behaviours follow from this shape:

  • Words match text; filters match whole values. A query is matched word by word against text fields. A filter compares the whole stored value, ignoring only case and accents: tags.name=news matches the tag "News", but name=Search matches only a record titled exactly "Search". A value longer than 190 characters is not kept for filtering at all, so a filter on a long text never matches.
  • Without a query there is no score. The answer above, a lookup by filters alone, scores 0. A list run without a query needs a sort, or its order is arbitrary (How results are ranked).
  • A result is drawn from its document. Anything the document lacks, such as an image, comes from loading the record itself, at one database query per result (What the template receives).

Mapping an area into a field, and making one field serve pages, posts and products alike, is on Search fields.

Why a new record is not instantly findable

Indexing runs in the background, so a record published a moment ago may not be found yet: seconds on a quiet site, minutes during a reindex or a large import. What to tell a client, the request that tells a delay from a misconfiguration, and the causes in the order to check them are on Why a new record is not findable yet.

Go deeper

Was this page helpful?

Your answer goes to the docs team.