CMS'te CEL ifadeleri yazmak için pratik bir rehber.
CMS'de CEL ifadeleri yazmak için pratik bir rehber.
CEL (Common Expression Language), CMS'imize yerleşik, hafif bir betik dilidir. Belgelerden veri çekmenizi, URL parametrelerini okumanızı ve değerleri anında hesaplamanızı sağlar.
Bir CEL betiği çalıştırıldığında, ifade verileri okur ve hesaplanmış bir sonuç döndürür. CEL'i salt okunur bir sorgu dili olarak düşünün. Veritabanındaki hiçbir şeyi değiştiremez; yalnızca verileri okur ve sonuç döndürür. Bu nedenle CMS'in her yerinde güvenle kullanılabilir.
Her CEL ifadesi üç nesneye erişebilir:
| Nesne | Açıklama | Örnek |
|---|---|---|
documents | CMS'ten herhangi bir belgeyi getirir | documents.get("country", "us") |
meta | Geçerli istek hakkındaki bilgiler (yerel ayar, URL parametreleri) | meta.locale, meta.params.slug |
schema | Geçerli belgenin alan tanımları | schema.fields |
doc ile Kendine Referans VermeBir belge düzenleyicisinde CEL ifadeleri yazarken, geçerli belgenin alan değerlerine doc nesnesiyle erişebilirsiniz. Bu, hesaplanan alanları ve alanlar arası referansları mümkün kılar.
// Geçerli belgenin fiyat alanına eriş
doc.price
// Geçerli belgenin alanlarından toplamı hesapla
doc.price * doc.quantity
// Geçerli belgenin durumuna göre koşul
doc.status == "published" ? doc.title : "Taslak: " + doc.title
doc nesnesi, düzenlenen belgedeki tüm alan değerlerini içerir. Şunlar için kullanışlıdır:
doc.price * doc.quantity)CEL'in en güçlü özelliği, CMS'in herhangi bir yerinden belge getirebilmesidir.
Söz dizimi: documents.get(schemaName, identifier)
welcome-post tanımlayıcısıyla kaydedilmiş bir article belgeniz olduğunu varsayalım:
{
"headline": "Platformumuza Hoş Geldiniz",
"author": "Sarah Chen",
"body": "Duyurmaktan mutluluk duyuyoruz...",
"tags": ["duyuru", "haber"]
}
Belgenin tamamını getirmek için:
documents.get("article", "welcome-post")
Yalnızca başlığı getirmek için:
documents.get("article", "welcome-post").headline
Sonuç: "Platformumuza Hoş Geldiniz"
Yazarı getirmek için:
documents.get("article", "welcome-post").author
Sonuç: "Sarah Chen"
Sayfanızda /articles/[slug] gibi dinamik rotalar olduğunda, URL parametresini almak ve doğru belgeyi getirmek için meta.params kullanabilirsiniz.
/articles/welcome-post adresi ziyaret edildiğinde:
documents.get("article", meta.params.slug).headline
Sonuç: "Platformumuza Hoş Geldiniz"
Dinamik sayfalar bu şekilde oluşturulur. Aynı CEL betiği, URL'deki slug değerini kullanarak tüm makalelerde çalışır.
Söz dizimi: documents.find(schemaName) veya documents.find(schemaName, filter)
// Tüm ülkeleri getir
documents.find("country")
// Filtreyle ülkeleri getir
documents.find("country", { "where": { "code": "us" } })
Filtreler where koşulları kullanır ve sonuç olarak belge dizisi döndürür.
CEL, çevrilmiş belge içeriğini iki şekilde getirir: yerel ayara dayalı otomatik çeviri ve açık çeviri araması.
meta.locale ile Otomatik Çevirimeta.locale ayarlandığında (örneğin rota parametrelerinden veya kullanıcı tercihlerinden), documents.get() çevrilmiş içeriği otomatik olarak birleştirir:
// meta.locale "fr" ise, temel belgeyle birleştirilmiş Fransızca çeviriyi döndürür
documents.get("greeting", "welcome").headline
Çalışma adımları:
meta.locale, en veya en-US değilse translations tablosunda çeviri aranır.{ ...baseContent, ...translatedContent }Böylece çevrilmiş alanlar temel alanların üzerine yazılır; çevrilmemiş alanlar ise temel belgeden alınır.
documents.translated() ile Açık ÇeviriGeçerli yerel ayardan bağımsız olarak belirli bir çeviriyi almak için:
Söz dizimi: documents.translated(schemaName, identifier, locale)
// Her zaman İspanyolca çeviriyi getir
documents.translated("greeting", "welcome", "es").headline
// URL parametresine göre çeviriyi getir
documents.translated("product", meta.params.id, meta.params.lang).description
// Çevirileri karşılaştır
documents.translated("article", "intro", "en").title + " / " + documents.translated("article", "intro", "fr").title
Eksik çeviriler için null kontrolü ve koşullu geri dönüş kullanabilirsiniz.
hero-block bileşeninin, article belgesinden alınan bir başlığı göstermesi gerekiyorsa:
documents.get("article", "homepage-hero").headline
Sonuç: Hero, "Daha Hızlı Oluşturun, Daha Akıllıca Yayınlayın" metnini gösterir.
/countries/[code] adresinde tam ülke adını göstermek için:
documents.get("country", meta.params.code).name
/countries/us ziyaret edildiğinde meta.params.code değeri "us" olur ve sonuç "Amerika Birleşik Devletleri" şeklindedir.
meta.locale == "ar-SA" ? "Herkese hoş geldiniz" : "Hoş geldiniz"
documents.get("country", documents.get("article", "us-news").countryCode).name
Önce makale getirilir, countryCode alanı çıkarılır, ardından ilgili ülke getirilerek name alanı alınır.
documents.get("article", meta.params.slug) != null
? documents.get("article", meta.params.slug).headline
: "Makale Bulunamadı"
Belirli bir alanı kontrol etmek için de aynı koşullu yapı kullanılabilir.
"featured" in documents.get("article", "welcome-post").tags
Makalenin etiketi varsa true döner.
documents.get("article", "welcome-post").tags[0]
size(documents.get("article", "welcome-post").tags)
İlk ifade ilk etiketi, ikinci ifade etiket sayısını döndürür.
meta.paramsParametreli rotalar dinamik ve yerelleştirilmiş sayfalar oluşturmanın temelidir. /{lang}/landingPage gibi bir rota tanımladığınızda CMS, URL'deki parametreleri çıkarır ve meta.params üzerinden kullanılabilir hale getirir.
Dinamik bölümler :paramName veya {paramName} söz dizimiyle tanımlanır:
| Desen | Örnek URL | Çıkarılan Parametreler |
|---|---|---|
/:lang/landingPage | /ko/landingPage | { lang: "ko" } |
/{country}/{lang}/products | /us/en/products | { country: "us", lang: "en" } |
/articles/:slug | /articles/welcome-post | { slug: "welcome-post" } |
Parametreler doğrulama amacıyla belge şemalarına bağlanabilir:
{
"pattern": "/{lang}/landingPage",
"param_bindings": {
"lang": "language"
}
}
Bu bağlantı CMS'e şunları söyler:
lang bölümünü çıkar.language şemasına göre doğrula.Yerelleştirilmiş içeriği getirmek için:
documents.get("greeting", meta.params.lang).headline
/ko/landingPage, /en/landingPage ve /ja/landingPage adresleri, sırasıyla ko, en ve ja belgelerinin başlığını getirir.
/{country}/{lang}/products gibi rotalar için:
{
"pattern": "/{country}/{lang}/products",
"param_bindings": {
"country": "country",
"lang": "language"
}
}
// Ülke adını getir
documents.get("country", meta.params.country).name
// Ülkeye göre yerelleştirilmiş ürün listesini getir
documents.find("product", { "where": { "country": meta.params.country } })
// Kullanıcının dilinde ülkeye özel selamlama
documents.get("greeting", meta.params.lang).headline + " - " + documents.get("country", meta.params.country).name
CMS parametreleri hiyerarşik olarak doğrular: önce ülke, sonra dil ve isteğe bağlı olarak dilin ülkenin languages[] dizisinde bulunup bulunmadığı kontrol edilir.
meta.segments - Ham URL Yoluna Erişimmeta.segments, ham URL yolunu bir dizi olarak sunar:
| URL yolu | meta.segments |
|---|---|
/articles/tech/ai-news | ["articles", "tech", "ai-news"] |
/ko/landingPage | ["ko", "landingPage"] |
/ | [] |
meta.segments ve meta.params Ne Zaman Kullanılmalı| Kullanım | En iyi yaklaşım |
|---|---|
| Rota desenindeki adlandırılmış parametreler | meta.params.lang |
| Konuma dayalı erişim | meta.segments[0] |
| Yol derinliğini alma | size(meta.segments) |
| Yolun bir bölüm içerip içermediğini kontrol etme | "admin" in meta.segments |
// İlk bölümü al
meta.segments[0]
// Yol derinliğini kontrol et
size(meta.segments) > 2 ? "derin" : "sığ"
// Yönetici bölümünde olup olmadığını kontrol et
"admin" in meta.segments ? "yönetici modu" : "genel mod"
// Parametre bağlı değilse bölümü kullan
has(meta.params.lang) ? meta.params.lang : meta.segments[0]
meta Nesnesi Başvurusumeta nesnesi geçerli istek hakkındaki tüm bağlamı içerir:
| Özellik | Tür | Açıklama |
|---|---|---|
meta.locale | string | Geçerli yerel ayar kodu (ör. "en-US", "ko-KR", "ar-SA") |
meta.params | Record<string, string> | URL deseninden çıkarılan rota parametreleri |
meta.segments | string[] | Bölümlere ayrılmış URL yolu |
meta.docId | string \| null | Geçerli belge UUID'si; yeni belgelerde null |
meta.title | string | Geçerli belgenin başlığı |
meta.localeYerel ayar kodu BCP 47 biçimini izler:
// RTL dillerini kontrol et
meta.locale == "ar-SA" || meta.locale == "he-IL" ? "rtl" : "ltr"
// Dil bölümünü almak için rota parametresini kullan
meta.params.lang
meta.paramsRota parametreleri her zaman dizedir:
meta.params.lang
meta.params.country
meta.params.slug
has(meta.params.category)
documents.get("greeting", meta.params.lang)
documents.ref("airports").get(meta.params.code)
meta.segmentsmeta.segments[0]
meta.segments[1]
size(meta.segments)
"products" in meta.segments
meta.docIdmeta.docId != null ? "düzenleniyor" : "yeni oluşturuluyor"
meta.docId != null ? documents.get("article", meta.docId).status : "taslak"
meta.title"Düzenleniyor: " + meta.title
meta.title.contains("Taslak") ? "devam eden çalışma" : "yayında"
documents.ref() - Zincirleme AramalarŞema biliniyor ancak tanımlayıcı dinamikse daha temiz bir söz dizimi kullanabilirsiniz:
// Geleneksel yaklaşım
documents.get("airports", meta.params.code).name
// ref() kullanımı
documents.ref("airports").get(meta.params.code).name
İki yaklaşım eşdeğerdir; ancak ref() dinamik bölümü daha anlaşılır kılar.
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
meta.params.xyz
meta.segments
meta.segments[0]
meta.docId
meta.title
doc.fieldName
== != < <= > >=
&& || !
condition ? valueIfTrue : valueIfFalse
"value" in listOrMap
size(list)
size(string)
"text".startsWith("te")
"text".endsWith("xt")
"text".contains("ex")
has(object.property)
hasProperty(obj, "key")
| Hata | Anlamı |
|---|---|
SYNTAX_ERROR | Betikte yazım hatası var |
TYPE_ERROR | Birbiriyle uyumsuz türler kullanılıyor |
RUNTIME_ERROR | Betik çalışırken bir sorun oluştu |
FETCH_LIMIT_EXCEEDED | Çok fazla belge getiriliyor (en fazla 50) |
TIMEOUT | Betik çok uzun sürdü (en fazla 5 saniye) |
AST_DEPTH_EXCEEDED | İfade çok derin iç içe geçmiş (en fazla 50) |
SCRIPT_TOO_LONG | Betik 5000 karakter sınırını aşıyor |
CEL motoru genişletilebilir olacak şekilde tasarlanmıştır. Planlanan yetenekler arasında MCP sunucusu entegrasyonu ve yapay zekâ özellikleri bulunur:
// Gelecekte: MCP aracılığıyla harici hizmetleri çağır
mcp.translate(meta.params.text, "en", meta.params.lang)
mcp.analyze(documents.get("article", meta.params.id).body)
// Gelecekte: Yapay zekâ destekli içerik üretimi
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"])
Bu yetenekler, mevcut betiklerle geriye dönük uyumluluk korunarak kayıtlı işlev sistemi üzerinden eklenecektir.
documents. veya meta. yazdığınızda kullanılabilir seçenekler gösterilir.documents.get("schema", "id") ile test edin, sonra .fieldName ekleyin.!= null ? ... : ... ile geri dönüş ekleyin.documents.get() veya documents.find() çağrısı 50 getirme sınırına dahildir.meta.segments yerine meta.params kullanmayı tercih edin - Adlandırılmış parametreler doğrulanır ve daha güvenilirdir.has() kullanın.documents.ref() kullanın.doc.fieldName kullanın.Bu bölüm, belgeleri birbirine bağlamak ve ilişkisel içerik yapıları oluşturmak için gelişmiş kalıpları açıklar.
Bir belgenin diğerine tanımlayıcı üzerinden referans vermesinin en basit biçimi:
// Makale yazar kimliğini saklar; yazarın adını getir
documents.get("author", documents.get("article", "intro").authorId).name
documents.ref() ile Zincirleme Aramalardocuments.get("country", documents.get("airport", meta.params.code).countryCode).name
documents.ref("country").get(documents.get("airport", meta.params.code).countryCode).name
// Havaalanı → Ülke → Bölge → Kıta
documents.get("continent",
documents.get("region",
documents.get("country",
documents.get("airport", meta.params.code).countryCode
).regionCode
).continentCode
).name
// Bir havaalanı için yerelleştirilmiş ülke adını getir
documents.translated("country",
documents.get("airport", meta.params.code).countryCode,
meta.params.lang
).name
Belgeler UUID veya anlamsal kodlarla birbirlerine referans verebilir. Geçerli belgenin değerlerine göre ilişkili belgeleri getirmek için doc kullanılabilir:
// Ürün belgesinde ilişkili kategori ayrıntılarını getir
documents.get("category", doc.categoryId).description
// Ürünün menşe ülkesine göre kargo ücretini hesapla
documents.get("shipping-rates", doc.originCountry).baseRate * doc.weight
Polimorfik referanslarda kaynak şemasına göre koşullu arama yapılabilir:
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
Her documents.get(), documents.find() ve documents.ref().get() çağrısı önbellek geçersizleştirme amacıyla izlenir. Referans verilen belge değiştiğinde CMS, hangi CEL ifadelerinin yeniden değerlendirilmesi gerektiğini bilir.
schema:identifier - Belirli belge bağımlılığıschema:identifier - Zincirli söz dizimiyle get ile aynıschema:* - Şema düzeyinde bağımlılıkBu örnek, /{lang}/landingPage adresinden erişilebilen çok dilli bir açılış sayfası oluşturur.
CMS yönetiminde greeting adında özel bir şema oluşturun:
{
"name": "greeting",
"fields": [
{ "name": "code", "type": "string", "required": true },
{ "name": "headline", "type": "string", "required": true },
{ "name": "subheadline", "type": "string" },
{ "name": "ctaText", "type": "string" },
{ "name": "ctaUrl", "type": "string" }
]
}
Her dil için belgeler oluşturun. Örneğin greeting/ko, greeting/en ve greeting/ja belgeleri code, headline, subheadline, ctaText ve ctaUrl alanlarını içerir.
/{lang}/landingPagelang → language bileşeni{
"lang": "language"
}
// Başlık
documents.get("greeting", meta.params.lang).headline
// Alt başlık
documents.get("greeting", meta.params.lang).subheadline
// CTA metni
documents.get("greeting", meta.params.lang).ctaText
// CTA URL'si
documents.get("greeting", meta.params.lang).ctaUrl
Catch-all rota ekleyin. ParametricRoutePage sayfayı çözümler, URL'den meta.params değerlerini çıkarır, CEL bağlantılarını sunucu tarafında değerlendirir ve her bloğu kayıt defteriniz üzerinden oluşturur.
// app/[...slug]/page.tsx
import ParametricRoutePage from 'cms-renderer/lib/renderer';
import { registry } from '@/lib/registry';
import { cmsConfig } from '@/lib/cms-config';
export const dynamic = 'force-static';
interface PageProps {
params: Promise<{ slug: string[] }>;
}
export default async function Page({ params }: PageProps) {
const { slug } = await params;
return (
<ParametricRoutePage
registry={registry}
apiKey={cmsConfig.apiKey}
websiteId={cmsConfig.websiteId}
cmsUrl={cmsConfig.cmsUrl}
params={Promise.resolve({ slug })}
/>
);
}
| URL | Beklenen Başlık |
|---|---|
/ko/landingPage | 환영 |
/en/landingPage | Hoş geldiniz |
/ja/landingPage | いらっしゃいませ |
Kullanıcı /ko/landingPage adresini ziyaret ettiğinde:
/{lang}/landingPage desenini eşleştirir.meta.params.lang = "ko" olur."ko" değerinin language şemasında bulunduğunu doğrular.documents.get("greeting", meta.params.lang) Korece içeriğe çözülür.interface CelMeta {
/** Geçerli yerel ayar kodu (ör. 'en-US') */
locale: string;
/** URL'den çıkarılan rota parametreleri */
params: Record<string, string>;
/** URL yol bölümleri */
segments: string[];
/** Geçerli belge kimliği */
docId: string | null;
/** Geçerli belge başlığı */
title: string;
}
extractParams işlevi URL yollarını işler:
Desen: /{country}/{lang}/products
Yol: /us/en/products
Algoritma:
1. Her ikisini normalleştir (sondaki eğik çizgileri kaldır)
2. Bölümlere ayır
3. Bölüm sayılarını karşılaştır
4. Her bölüm çifti için:
- Desen : veya {} ile başlıyorsa parametre olarak çıkar
- Aksi halde tam eşleşme gerekir
5. Şunu döndür: { country: "us", lang: "en" }
// Basit bağlama
{ "lang": "language" }
// Ayrıntılı bağlama
{
"lang": {
"schemaName": "language",
"slugField": "code"
},
"slug": {
"schemaName": "article",
"slugField": "slug"
}
}
documents.get(schema, identifier) ile arama yapılırken:
id ile aranır.content.code alanı kontrol edilir.content.slug alanı kontrol edilir.title alanı kontrol edilir.Bu sayede belgeler benzersiz olan herhangi bir tanımlayıcıyla esnek biçimde referanslanabilir.