profound-logoProfound CMS
⌘K
Admin
Theme
DocsTutorialBlogPhilosophy
DocsTutorialBlogPhilosophy

Hybrid

Collection of Pages with ComponentsТипове компонентиSetup server sent events (SSE) content refetchInstall Profound CMS as a proxyСкриптове в конструктора на шаблониProject ScaffoldingМедийна библиотека

Без глава

Бърз стартSplit Screen JSON Component Builder with LLMComponent Zod Pull

REST API

Преглед на REST APIgetСвързване на уебсайт към CMS APIgetGET /routesgetGET /routegetGET /blocksgetВземане на блокове с CEL кешgetGET /blocks/generatedgetGET /componentsgetGET /components/{name}getGET /dataset/{schema_name}getGET /content-changes (SSE)patchPATCH /dataset/{schema_name}postПревод на публикацияpatchPATCH /translationsgetПолучаване на използванетоpostPOST /csvpatchPATCH /csv
All Systems Operational
Powered Byprofound-logo
Theme

Скриптове в конструктора на шаблони

Практическо ръководство за писане на CEL изрази в CMS.

Практическо ръководство за писане на CEL изрази в CMS.


Как работи CEL

CEL (Common Expression Language) е лек скриптов език, вграден в нашата CMS. Той ви позволява да пишете динамични изрази, които извличат данни от документи, четат параметри от URL адреси и изчисляват стойности в движение.

Ето какво се случва, когато се изпълни CEL скрипт:

Вашият скрипт                  Енджинът                      Резултат
    |                              |                              |
    v                              v                              v
documents.get("article", "intro") --> Извлича от базата данни --> { headline: "Welcome", body: "..." }
         .headline                --> Извлича полето         --> "Welcome"

Мислете за CEL като за език за заявки само за четене. Той не може да променя нищо в базата данни — само чете данни и връща изчислен резултат. Това го прави безопасен за използване навсякъде в CMS.


Основни градивни елементи

Всеки CEL израз има достъп до три неща:

ОбектКакво представляваПример
documentsИзвлича всеки документ от CMSdocuments.get("country", "us")
metaИнформация за текущата заявка (локал, URL параметри)meta.locale, meta.params.slug
schemaДефинициите на полетата на текущия документschema.fields

Саморефериране с doc

Когато пишете CEL изрази в редактора на документ, можете да получите достъп до стойностите на полетата на текущия документ чрез обекта doc. Това позволява изчисляеми полета и препратки между полета.

// Достъп до полето за цена на текущия документ
doc.price

// Изчисляване на общата стойност от полетата на текущия документ
doc.price * doc.quantity

// Условие според статуса на текущия документ
doc.status == "published" ? doc.title : "Чернова: " + doc.title

Обектът doc съдържа всички стойности на полетата от редактирания документ. Той е полезен за:

  • Изчисляеми полета (напр. doc.price * doc.quantity)
  • Логика за условно показване според състоянието на документа
  • Изрази за валидация

Извличане на документи

Най-мощната функция на CEL е извличането на документи от всяко място във вашата CMS.

Получаване на един документ

Синтаксис: documents.get(schemaName, identifier)

Да предположим, че имате документ article, съхранен с идентификатор "welcome-post":

// Съхранено в CMS като: article / welcome-post
{
  "headline": "Добре дошли в нашата платформа",
  "author": "Sarah Chen",
  "body": "Радваме се да обявим...",
  "tags": ["announcement", "news"]
}

За да извлечете целия документ:

documents.get("article", "welcome-post")

Връща: целия документ.

За да извлечете само заглавието:

documents.get("article", "welcome-post").headline

Връща: "Добре дошли в нашата платформа"

За да извлечете автора:

documents.get("article", "welcome-post").author

Връща: името на автора.


Използване на URL параметри

Когато страницата ви има динамични маршрути (например /articles/[slug]), можете да използвате meta.params, за да получите URL параметъра и да извлечете правилния документ.

Ако някой посети /articles/welcome-post:

documents.get("article", meta.params.slug).headline

Връща: заглавието на статията.

Така се изграждат динамични страници — един и същ CEL скрипт работи за всяка статия, като използва съответния slug от URL адреса.


Извличане на множество документи

Синтаксис: documents.find(schemaName) или documents.find(schemaName, filter)

// Получаване на всички държави
documents.find("country")

Връща:

[
  { "code": "us", "name": "Съединени щати", "flag": "US" },
  { "code": "sa", "name": "Саудитска Арабия", "flag": "SA" },
  { "code": "gb", "name": "Обединеното кралство", "flag": "GB" }
]
// Получаване на държави с филтър
documents.find("country", { "where": { "code": "us" } })

Преводи

CEL поддържа извличане на преведено съдържание по два начина: автоматичен превод според локала и явно търсене на превод.

Автоматичен превод чрез meta.locale

Когато meta.locale е зададен (например чрез параметри на маршрута или предпочитанията на потребителя), documents.get() автоматично обединява преведеното съдържание:

// Ако meta.locale е "fr", връща френския превод, обединен с основния документ
documents.get("greeting", "welcome").headline

Как работи:

  1. Извлича съдържанието на основния документ
  2. Ако meta.locale не е "en" или "en-US", търси превод в таблицата translations
  3. Обединява преведените полета с основното съдържание: { ...baseContent, ...translatedContent }

Това означава, че преведените полета заменят основните, а непреведените полета използват стойностите от основния документ.

Явен превод с documents.translated()

Когато трябва да извлечете конкретен превод независимо от текущия локал:

Синтаксис: documents.translated(schemaName, identifier, locale)

// Винаги извлича испанския превод
documents.translated("greeting", "welcome", "es").headline

// Извлича превод според параметър от URL
documents.translated("product", meta.params.id, meta.params.lang).description

// Сравнява преводи
documents.translated("article", "intro", "en").title + " / " + documents.translated("article", "intro", "fr").title

Пример за превод

Документи за поздрав с преводи:

// Основен документ: greeting / welcome
{ "headline": "Добре дошли", "subheadline": "Добре дошли в нашата платформа" }

// Превод (език: "fr")
{ "headline": "Bienvenue", "subheadline": "Bienvenue sur notre plateforme" }

// Превод (език: "es")
{ "headline": "Bienvenido", "subheadline": "Bienvenido a nuestra plataforma" }

CEL скриптове:

// С meta.locale = "fr"
documents.get("greeting", "welcome").headline
// Връща: "Bienvenue"

// Явен испански превод
documents.translated("greeting", "welcome", "es").headline
// Връща: "Bienvenido"

// Шаблон с резервна стойност при липсващ превод
documents.translated("greeting", "welcome", meta.params.lang) != null
  ? documents.translated("greeting", "welcome", meta.params.lang).headline
  : documents.get("greeting", "welcome").headline

Примери от реалния свят

Пример 1: Заглавие на hero блок от друг документ

Имате hero-block, който трябва да показва заглавие, извлечено от документ article.

CEL скриптът в полето за заглавие на hero блока е:

documents.get("article", "homepage-hero").headline

Резултат: Hero блокът показва заглавието от документа.


Пример 2: Име на държава от код

Изграждате страница на /countries/[code] и искате да покажете пълното име на държавата.

documents.get("country", meta.params.code).name

Когато някой посети /countries/us:

  • meta.params.code = "us"
  • Резултат: "Съединени щати"

Пример 3: Условно съдържание според локала

Показване на различни заглавия според локала на потребителя.

meta.locale == "ar-SA" ? "Добре дошли на всички" : "Добре дошли"

Пример 4: Свързани търсения на документи

Ако вашият article има поле countryCode, можете да получите пълното име на държавата:

documents.get("country", documents.get("article", "us-news").countryCode).name

CEL изпълнява вложеното търсене, извлича countryCode, след което използва получената стойност за намиране на държавата.


Пример 5: Резервни стойности

Ако даден документ може да не съществува, можете да зададете резервна стойност:

documents.get("article", meta.params.slug) != null
  ? documents.get("article", meta.params.slug).headline
  : "Статията не е намерена"

Можете да проверите и дали съществува конкретно поле:

documents.get("article", "intro").author != null
  ? documents.get("article", "intro").author
  : "Неизвестен автор"

Пример 6: Работа със списъци

Проверка дали статията има определен етикет:

"featured" in documents.get("article", "welcome-post").tags

Връща: true, ако статията има етикета featured.

Получаване на първия етикет:

documents.get("article", "welcome-post").tags[0]

Броене на етикетите:

size(documents.get("article", "welcome-post").tags)

Параметрични маршрути и meta.params

Параметричните маршрути са ключът към изграждането на динамични, локализирани страници. Когато дефинирате шаблон на маршрут като /{lang}/landingPage, CMS извлича параметрите от URL адреса и ги предоставя чрез meta.params.

Как работят параметрите на маршрута

Маршрутите използват синтаксиса :paramName или {paramName} за дефиниране на динамични сегменти:

ШаблонПримерен URLИзвлечени параметри
/:lang/landingPage/ko/landingPage{ lang: "ko" }
/{country}/{lang}/products/us/en/products{ country: "us", lang: "en" }
/articles/:slug/articles/welcome-post{ slug: "welcome-post" }

Всеки параметър на маршрута може да бъде свързан със схема на документ за валидация:

{
  "pattern": "/{lang}/landingPage",
  "param_bindings": {
    "lang": "language"
  }
}

Това указва на CMS да:

  1. Извлече сегмента lang от URL адреса
  2. Го валидира спрямо схемата language
  3. При успех да предостави целия документ в разрешените параметри

Пример: Целева страница според езика

documents.get("greeting", meta.params.lang).headline
URLmeta.params.langРезултат
/ko/landingPage"ko"заглавие на корейски
/en/landingPage"en"заглавие на английски
/ja/landingPage"ja"заглавие на японски

Разширен шаблон: маршрути държава + език

За маршрути като /{country}/{lang}/products:

{
  "pattern": "/{country}/{lang}/products",
  "param_bindings": {
    "country": "country",
    "lang": "language"
  }
}
// Получаване на името на държавата
documents.get("country", meta.params.country).name

// Получаване на локализиран списък с продукти според държавата
documents.find("product", { "where": { "country": meta.params.country } })

// Комбинирано: поздрав според държавата и езика на потребителя
documents.get("greeting", meta.params.lang).headline + " от " + documents.get("country", meta.params.country).name

CMS валидира параметрите йерархично:

  1. Валидира параметъра country спрямо схемата country
  2. Валидира параметъра lang спрямо схемата language
  3. По желание проверява дали lang присъства в масива country.languages[]

meta.segments — достъп до необработения път на URL адреса

meta.segments предоставя необработения път на URL адреса като масив. Това е полезно, когато ви е необходим достъп по позиция без именувани параметри.

Път на URLmeta.segments
/articles/tech/ai-news["articles", "tech", "ai-news"]
/ko/landingPage["ko", "landingPage"]
/us/en/products/featured["us", "en", "products", "featured"]
/[]

Кога да използвате meta.segments вместо meta.params

Случай на употребаНай-добър подход
Именувани параметри от шаблона на маршрутаmeta.params.lang
Достъп по позицияmeta.segments[0]
Получаване на дълбочината на пътяsize(meta.segments)
Проверка дали пътят съдържа сегмент"admin" in meta.segments
// Получаване на първия сегмент
meta.segments[0]

// Проверка на дълбочината на пътя
size(meta.segments) > 2 ? "дълбок" : "плитък"

// Проверка дали сме в административната секция
"admin" in meta.segments ? "административен режим" : "публичен режим"

// Резервен вариант: използване на сегмент, ако параметърът не е свързан
has(meta.params.lang) ? meta.params.lang : meta.segments[0]

Пълна справка за обекта meta

Обектът meta съдържа целия контекст на текущата заявка:

СвойствоТипОписание
meta.localestringТекущ код на локала (напр. "en-US", "ko-KR", "ar-SA")
meta.paramsRecord<string, string>Параметри на маршрута, извлечени от URL шаблона
meta.segmentsstring[]URL пътят, разделен на сегменти
meta.docIdstring | nullUUID на текущия документ (null за нови документи)
meta.titlestringЗаглавие на текущия документ

meta.locale

Кодът на локала следва формата BCP 47 (език-регион):

// Проверка за езици с писане отдясно наляво
meta.locale == "ar-SA" || meta.locale == "he-IL" ? "rtl" : "ltr"

// Получаване само на езиковата част
meta.locale.split("-")[0]  // Не се поддържа — използвайте meta.params.lang

meta.params

Параметрите на маршрута винаги са низове. CMS ги валидира спрямо свързаните схеми преди оценяването:

// Достъп до именуван параметър
meta.params.lang           // "ko"
meta.params.country        // "us"
meta.params.slug           // "welcome-post"

// Проверка дали параметърът съществува
has(meta.params.category)  // true/false

// Използване при извличане на документ
documents.get("greeting", meta.params.lang)
documents.ref("airports").get(meta.params.code)

meta.segments

Необработените URL сегменти като масив:

meta.segments[0]           // Първи сегмент
meta.segments[1]           // Втори сегмент
size(meta.segments)        // Брой сегменти
"products" in meta.segments  // Съдържа ли пътят "products"?

meta.docId

UUID на текущия документ, полезен за саморефериращи се скриптове:

meta.docId != null ? "редактиране" : "създаване на нов документ"
meta.docId != null ? documents.get("article", meta.docId).status : "чернова"

meta.title

Заглавието на текущия документ:

"Редактиране: " + meta.title
meta.title.contains("Draft") ? "в процес на работа" : "публикувано"

documents.ref() — свързани търсения

За по-чист синтаксис, когато схемата е известна, но идентификаторът е динамичен:

// Традиционен подход
documents.get("airports", meta.params.code).name

// С ref() — схемата е отделена от динамичния идентификатор
documents.ref("airports").get(meta.params.code).name

И двата подхода са еквивалентни, но ref() прави динамичната част по-ясна.


Бърза справка

Извличане на документи

documents.get("schema", "identifier")       // Получаване на един документ
documents.get("schema", "id").fieldName     // Получаване на конкретно поле
documents.find("schema")                    // Получаване на всички документи
documents.find("schema", { "where": {...}}) // Заявка с филтър
documents.ref("schema").get(identifier)     // Свързано търсене
documents.translated("schema", "id", "fr")  // Получаване с изрично зададен локал

Контекстни променливи

meta.locale          // "en-US", "ar-SA" и др.
meta.params.xyz      // URL параметър с име "xyz"
meta.segments        // URL път като масив: ["articles", "intro"]
meta.segments[0]     // Първи сегмент от пътя
meta.docId           // ID на текущия документ (или null)
meta.title           // Заглавие на текущия документ
doc.fieldName        // Стойност на поле от текущия документ (в контекст на редактора)

Оператори

// Сравнение
==  !=  <  <=  >  >=

// Логика
&&  ||  !

// Тернарен оператор (ако-иначе)
condition ? valueIfTrue : valueIfFalse

// Членство
"value" in listOrMap

Често използвани функции

size(list)                    // Брой елементи
size(string)                  // Дължина на низ
"text".startsWith("te")       // true
"text".endsWith("xt")         // true
"text".contains("ex")         // true
has(object.property)          // Проверка дали свойството съществува
hasProperty(obj, "key")       // Проверка дали обектът има ключ (алтернативен синтаксис)

Съобщения за грешки

Ако нещо се обърка, ще видите едно от следните съобщения:

ГрешкаКакво означава
SYNTAX_ERRORПравописна грешка в скрипта (липсваща кавичка, неправилен оператор)
TYPE_ERRORСмесвате типове, които не могат да се използват заедно
RUNTIME_ERRORСкриптът се е изпълнил, но е срещнал проблем (неопределена променлива)
FETCH_LIMIT_EXCEEDEDИзвличате твърде много документи (максимум 50)
TIMEOUTСкриптът се изпълнява твърде дълго (максимум 5 секунди)
AST_DEPTH_EXCEEDEDИзразът е прекалено дълбоко вложен (максимална дълбочина: 50)
SCRIPT_TOO_LONGСкриптът надвишава ограничението от 5000 знака

Разширяемост и бъдещи възможности

CEL енджинът е проектиран с възможност за разширяване. Планираните бъдещи възможности включват:

Планирано: интеграция с MCP сървър

// Бъдеще: извикване на външни услуги чрез MCP
mcp.translate(meta.params.text, "en", meta.params.lang)
mcp.analyze(documents.get("article", meta.params.id).body)

Планирано: възможности за AI

// Бъдеще: генериране на съдържание с AI
ai.summarize(documents.get("article", meta.params.id).body, 100)
ai.translate(meta.params.text, meta.params.targetLang)
ai.classify(meta.params.input, ["positive", "negative", "neutral"])

Тези възможности ще бъдат добавени чрез системата за регистрирани функции, като се запази обратната съвместимост със съществуващите скриптове.


Съвети

  1. Използвайте автоматично допълване — въведете documents. или meta. и редакторът ще покаже наличните опции
  2. Започнете просто — първо тествайте с documents.get("schema", "id"), след което добавете .fieldName
  3. Проверявайте за null — ако документът може да не съществува, добавете резервна стойност с != null ? ... : ...
  4. Не извличайте излишни данни — всяко documents.get() или documents.find() се брои към лимита от 50 извличания
  5. Предпочитайте meta.params пред meta.segments — именуваните параметри са валидирани и по-надеждни
  6. Използвайте has() за незадължителни параметри — проверете has(meta.params.category) преди достъп
  7. Използвайте documents.ref() за динамични идентификатори — по-ясен синтаксис, когато схемата е статична, но идентификаторът е динамичен
  8. Използвайте doc.fieldName за самореференции — достъпвайте полетата на текущия документ в изчисляеми изрази

Препратки между документи

Този раздел обхваща разширени шаблони за свързване на документи и изграждане на релационни структури от съдържание.

Основен шаблон за препратка

Най-простата форма е документ да препраща към друг чрез идентификатор.

// Статията съхранява ID на автора и извлича името му
documents.get("author", documents.get("article", "intro").authorId).name

Свързани търсения с documents.ref()

// Традиционен подход
documents.get("country", documents.get("airport", meta.params.code).countryCode).name

// С ref() — по-ясно, когато схемата е известна, но идентификаторът е динамичен
documents.ref("country").get(documents.get("airport", meta.params.code).countryCode).name

Многостепенни вериги от препратки

// Летище → Държава → Регион → Континент
documents.get("continent",
  documents.get("region",
    documents.get("country",
      documents.get("airport", meta.params.code).countryCode
    ).regionCode
  ).continentCode
).name

Препратка с превод

// Получаване на локализирано име на държавата за летище
documents.translated("country",
  documents.get("airport", meta.params.code).countryCode,
  meta.params.lang
).name

Шаблони за препратки според случая на употреба

Шаблон 1: Търсене по външен ключ

Документът съхранява ID, препращащо към друг документ.

// Разрешаване на името на автора
documents.get("author", documents.get("article", meta.params.slug).authorId).name

// Разрешаване на категория с резервна стойност
documents.get("article", meta.params.slug).categoryId != null
  ? documents.get("category", documents.get("article", meta.params.slug).categoryId).name
  : "Без категория"

Шаблон 2: Препратки чрез код

Документите препращат един към друг чрез смислови кодове вместо UUID.

// Верига Летище → Държава → Валута
documents.get("currency",
  documents.get("country",
    documents.get("airport", meta.params.code).countryCode
  ).currencyCode
).symbol

Шаблон 3: Самореференция с контекста на doc

Използвайте doc за изчисляеми полета, които препращат към други документи въз основа на стойностите на текущия документ.

// В документ за продукт: извличане на данни за свързаната категория
documents.get("category", doc.categoryId).description

// Изчисляване на разхода за доставка според държавата на произход
documents.get("shipping-rates", doc.originCountry).baseRate * doc.weight

Шаблон 4: Двупосочни препратки

Когато документите препращат един към друг, внимавайте с лимитите за извличане.

documents.find("article", { "where": { "authorId": documents.get("article", meta.params.slug).authorId } })

Шаблон 5: Полиморфни препратки

Когато дадено поле може да препраща към различни схеми:

documents.get("content-block", "hero-1").sourceType == "article"
  ? documents.get("article", documents.get("content-block", "hero-1").sourceId).headline
  : documents.get("product", documents.get("content-block", "hero-1").sourceId).name

Проследяване на зависимостите

Всяко извикване на documents.get(), documents.find() и documents.ref().get() се проследява за невалидиране на кеша. Когато рефериран документ се промени, CMS знае кои CEL изрази трябва да бъдат преизчислени.

Проследяваните зависимости включват:

  • get: schema:identifier — зависимост от конкретен документ
  • ref: schema:identifier — същото като get, чрез свързан синтаксис
  • query: schema:* — зависимост на ниво схема (всеки документ в схемата)

Най-добри практики за препратки

  1. Ограничете дълбочината на веригата — всяко ниво добавя забавяне и увеличава броя извличания
  2. Кеширайте междинните резултати — ако ви е нужна една и съща вложена стойност два пъти, извлечете родителя веднъж
  3. Използвайте проверки за null — препратките могат да се повредят, ако документите бъдат изтрити
  4. Предпочитайте кодове пред UUID — кодовете са по-четими и стабилни между среди
  5. Следете лимитите за извличане — сложните вериги могат бързо да достигнат лимита от 50 извличания

Приложение A: Пълен пример за параметричен маршрут

Това ръководство създава многоезична целева страница, достъпна на /{lang}/landingPage.

Стъпка 1: Създаване на схема за поздрав

В административния панел на CMS създайте персонализирана схема с име greeting.

Стъпка 2: Създаване на документи за поздрав

Създайте документи за всеки език, например greeting/ko, greeting/en и greeting/ja.

Стъпка 3: Създаване на страницата

Създайте страница със следната конфигурация:

  • Път/шаблон: /{lang}/landingPage
  • Състояние: Публикувано
  • Съпоставяне на динамични сегменти: съпоставете lang с компонента language
{
  "lang": "language"
}

Стъпка 4: Добавяне на блокове с CEL скриптове

Добавете hero блок към маршрута със следните CEL скриптове:

// Заглавие
documents.get("greeting", meta.params.lang).headline

// Подзаглавие
documents.get("greeting", meta.params.lang).subheadline

// Текст на CTA
documents.get("greeting", meta.params.lang).ctaText

// URL адрес на CTA
documents.get("greeting", meta.params.lang).ctaUrl

Стъпка 5: Използване в Next.js

Добавете catch-all маршрут. ParametricRoutePage разрешава страницата, извлича meta.params от URL адреса, оценява CEL свързванията от страна на сървъра и визуализира всеки блок чрез вашия registry — не е необходимо сами да изграждате контекста meta или да извиквате нискоуровневия клиент.

Стъпка 6: Тестване на маршрутите

Посетете следните URL адреси, за да видите локализираното съдържание:

URLОчаквано заглавие
/ko/landingPage환영
/en/landingPageДобре дошли
/ja/landingPageいらっしゃいませ

Как работи разрешаването

Когато потребител посети /ko/landingPage:

  1. Съпоставяне на маршрута: CMS съпоставя шаблона /{lang}/landingPage
  2. Извличане на параметъра: meta.params.lang = "ko"
  3. Валидация: CMS проверява дали "ko" съществува в схемата language
  4. Оценяване на CEL: скриптове като documents.get("greeting", meta.params.lang) се разрешават до корейско съдържание
  5. Отговор: локализираните блокове се връщат към клиента

Приложение B: Техническа справка

Интерфейс CelMeta (TypeScript)

interface CelMeta {
  /** Текущ код на локала (напр. 'en-US') */
  locale: string;
  /** Параметри на маршрута, извлечени от URL */
  params: Record<string, string>;
  /** Сегменти на URL пътя */
  segments: string[];
  /** ID на текущия документ (ако се редактира съществуващ документ) */
  docId: string | null;
  /** Заглавие на текущия документ */
  title: string;
}

Алгоритъм за извличане на параметри

Функцията extractParams обработва пътищата на URL адресите:

Шаблон: /{country}/{lang}/products
Път:     /us/en/products

Алгоритъм:
1. Нормализирайте и двата пътя (премахнете крайните наклонени черти)
2. Разделете ги на сегменти
3. Съпоставете броя на сегментите (трябва да е равен)
4. За всяка двойка сегменти:
   - Ако шаблонът започва с : или {}, извлечете параметъра
   - В противен случай сегментите трябва да съвпадат точно
5. Върнете: { country: "us", lang: "en" }

Поддържани формати за свързване на параметри

// Просто свързване (използва полето "code" за търсене)
{ "lang": "language" }

// Подробно свързване (персонализирано поле за slug)
{
  "lang": {
    "schemaName": "language",
    "slugField": "code"
  },
  "slug": {
    "schemaName": "article",
    "slugField": "slug"
  }
}

Приоритет при търсене на документи

При извличане чрез documents.get(schema, identifier):

  1. Съвпадение по UUID: ако идентификаторът е валиден UUID, извлича се по id
  2. Поле code: проверява се полето content.code
  3. Поле slug: проверява се полето content.slug
  4. Съвпадение по заглавие: проверява се полето title

Това позволява гъвкави препратки към документи чрез всеки уникален идентификатор.

Continue Reading
Previous‹Install Profound CMS as a proxyNextProject Scaffolding›