CMS'de CEL ifadeleri yazmaya yönelik pratik bir rehber.
CMS'de CEL ifadeleri yazmaya yönelik pratik bir rehber.
CEL (Common Expression Language), CMS'imize yerleşik hafif bir betik dilidir. Belgelerden veri çekmenize, URL parametrelerini okumanıza ve değerleri anında hesaplamanıza olanak tanıyan dinamik ifadeler yazmanızı sağlar.
Bir CEL betiği çalıştığında neler olur:
Betiğiniz Motor Sonuç
| | |
v v v
documents.get("article", "intro") --> Veritabanından alır --> { headline: "Welcome", body: "..." }
.headline --> Alanı çıkarır --> "Welcome"
CEL'i salt okunur bir sorgu dili gibi düşünebilirsiniz. Veritabanındaki hiçbir şeyi değiştiremez; sadece verileri okur ve hesaplanmış bir sonuç döndürür. Bu da onu CMS'nin her yerinde güvenle kullanabileceğiniz anlamına gelir.
Her CEL ifadesinin erişebildiği üç şey vardır:
| Nesne | Nedir | Örnek |
|---|---|---|
documents | CMS'den herhangi bir belgeyi getirir | documents.get("country", "us") |
meta | Geçerli isteğe dair bilgiler (yerel ayar, URL parametreleri) | meta.locale, meta.params.slug |
schema | Geçerli belgenin alan tanımları | schema.fields |
CEL'in en güçlü özelliği, CMS'nizdeki herhangi bir yerden belgeleri çekebilmesidir.
Sözdizimi: documents.get(schemaName, identifier)
Tanımlayıcısı "welcome-post" olan bir article belgeniz olduğunu varsayalım:
// CMS'de şu şekilde saklanır: article / welcome-post
{
"headline": "Welcome to Our Platform",
"author": "Sarah Chen",
"body": "We're excited to announce...",
"tags": ["announcement", "news"]
}
Belgenin tamamını getirmek için:
documents.get("article", "welcome-post")
Döndürür:
{
"headline": "Welcome to Our Platform",
"author": "Sarah Chen",
"body": "We're excited to announce...",
"tags": ["announcement", "news"]
}
Yalnızca başlığı getirmek için:
documents.get("article", "welcome-post").headline
Döndürür: "Welcome to Our Platform"
Yazarı getirmek için:
documents.get("article", "welcome-post").author
Döndürür: "Sarah Chen"
Sayfanız dinamik rotalara sahipse (örneğin /articles/[slug]), meta.params ile URL parametresini alıp doğru belgeyi getirebilirsiniz.
Birisi /articles/welcome-post adresini ziyaret ederse:
documents.get("article", meta.params.slug).headline
Döndürür: "Welcome to Our Platform"
Bu şekilde dinamik sayfalar oluşturursunuz — aynı CEL betiği, URL'deki slug ne olursa olsun her makale için çalışır.
Sözdizimi: documents.find(schemaName) veya documents.find(schemaName, filter)
// Tüm ülkeleri getir
documents.find("country")
Döndürür:
[
{ "code": "us", "name": "United States", "flag": "US" },
{ "code": "sa", "name": "Saudi Arabia", "flag": "SA" },
{ "code": "gb", "name": "United Kingdom", "flag": "GB" }
// Filtre ile ülkeleri getir
documents.find("country", { "where": { "code": "us" } })
Döndürür:
[
{ "code": "us", "name": "United States", "flag": "US" }
]
hero-block bileşeninizin, bir article belgesinden alınan başlığı göstermesi gerekiyor.
Makale belgeniz (tanımlayıcı: "homepage-hero"):
{
"headline": "Build Faster, Ship Smarter",
"subheadline": "The modern CMS for developers"
}
Hero bloğunun başlık alanındaki CEL betiği:
documents.get("article", "homepage-hero").headline
Sonuç: Hero, "Build Faster, Ship Smarter" metnini gösterir.
/countries/[code] adresinde bir sayfa oluşturuyor ve tam ülke adını göstermek istiyorsunuz.
Ülke belgeleriniz:
// country / us
{ "code": "us", "name": "United States", "flag": "US", "languages": ["en", "es"] }
// country / sa
{ "code": "sa", "name": "Saudi Arabia", "flag": "SA", "languages": ["ar", "en"
CEL betiği:
documents.get("country", meta.params.code).name
Birisi /countries/us adresini ziyaret ettiğinde:
meta.params.code = "us""United States"Birisi /countries/sa adresini ziyaret ettiğinde:
meta.params.code = "sa""Saudi Arabia"Kullanıcının yerel ayarına göre farklı başlıklar gösterin.
meta.locale == "ar-SA" ? "مرحبا بكم" : "Welcome"
Yerel ayar "ar-SA" ise: "مرحبا بكم" döner.
Yerel ayar başka bir şeyse: "Welcome" döner.
article belgenizde bir countryCode alanı var ve tam ülke adını almak istiyorsunuz.
Makale belgesi:
{ "headline": "News from the US", "countryCode": "us" }
CEL betiği:
documents.get("country", documents.get("article", "us-news").countryCode).name
Ne olur:
documents.get("article", "us-news") değeri { "headline": "News from the US", "countryCode": "us" } döndürür..countryCode "us" değerini çeker.documents.get("country", "us") değeri { "code": "us", "name": "United States", ... } döndürür..name "United States" değerini alır.Sonuç: "United States"
Bir belgenin olmayabileceği durumlarda yedek değer sağlayabilirsiniz:
documents.get("article", meta.params.slug) != null
? documents.get("article", meta.params.slug).headline
: "Article Not Found"
Ya da belirli bir alanın var olup olmadığını kontrol edin:
documents.get("article", "intro").author != null
? documents.get("article", "intro").author
: "Unknown Author"
Makalenizde etiketler var ve belirli bir etiketin olup olmadığını kontrol etmek istiyorsunuz:
"featured" in documents.get("article", "welcome-post").tags
Döndürür: Makalede "featured" etiketi varsa true.
İlk etiketi alın:
documents.get("article", "welcome-post").tags[0]
Döndürür: İlk etiketi "announcement".
Etiketleri sayın:
size(documents.get("article", "welcome-post").tags)
Döndürür: Etiket sayısını 2.
Parametrik rotalar, dinamik ve yerelleştirilmiş sayfalar oluşturmanın anahtarıdır. /{lang}/landingPage gibi bir rota deseni tanımladığınızda, CMS URL'den parametreleri çıkarır ve bunları meta.params aracılığıyla kullanılabilir hale getirir.
Rota Deseni Tanımı:
Rotalar dinamik bölümler tanımlamak için :paramName veya {paramName} sözdizimini kullanı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" } |
Parametre Bağlamaları: Her rota parametresi doğrulama için bir belge şemasına bağlanabilir:
{
"pattern": "/{lang}/landingPage",
"param_bindings": {
"lang": "language"
}
}
Bu bağlama CMS'ye şunu söyler:
lang segmentini çıkarlanguage şemasına göre doğrula (belgede content.code eşleşmesini arar)Rota yapılandırması:
/{lang}/landingPage/{lang}/landingPage{ "lang": "language" }Karşılama belgeleriniz:
// greeting / ko
{ "code": "ko", "headline": "환영합니다", "subheadline": "우리 플랫폼에 오신 것을 환영합니다" }
// greeting / en
{ "code": "en", "headline": "Welcome", "subheadline": "Welcome to our platform" }
// greeting / ja
{ "code": "ja", "headline"
Yerelleştirilmiş içeriği getirmek için CEL betiği:
documents.get("greeting", meta.params.lang).headline
Nasıl çözülür:
| URL | meta.params.lang | Sonuç |
|---|---|---|
/ko/landingPage | "ko" | "환영합니다" |
/en/landingPage | "en" | "Welcome" |
/ja/landingPage | "ja" | "ようこそ" |
/{country}/{lang}/products gibi rotalar için:
Rota yapılandırması:
{
"pattern": "/{country}/{lang}/products",
"param_bindings": {
"country": "country",
"lang": "language"
}
}
CEL betikleri:
// Ülke adını al
documents.get("country", meta.params.country).name
// Ülkeye göre yerelleştirilmiş ürün listesini al
documents.find("product", { "where": { "country": meta.params.country } })
// Birleştir: Kullanıcının dilinde ülkeye özel karşılama göster
documents.get("greeting", meta.params.lang).headline + " from " + documents.get("country", meta.params.country).name
Doğrulama zinciri:
CMS parametreleri hiyerarşik olarak doğrular. /{country}/{lang} rotaları için:
country parametresini country şemasına göre doğrularlang parametresini language şemasına göre doğrularlang değerinin country.languages[] dizisinde olup olmadığını kontrol eder (hiyerarşik doğrulama)meta.segments, adlandırılmış parametrelere ihtiyaç duymadan konumsal erişim gerektiğinde kullanışlı olan ham URL yolunu bir dizi olarak sağlar.
Nasıl çalışır:
| URL Yolu | meta.segments |
|---|---|
/articles/tech/ai-news | ["articles", "tech", "ai-news"] |
/ko/landingPage | ["ko", "landingPage"] |
/us/en/products/featured | ["us", "en", "products", "featured"] |
/ | [] |
| Kullanım Durumu | En İyi Yaklaşım |
|---|---|
| Rota deseninden adlandırılmış parametreler | meta.params.lang |
| Konuma dayalı erişim | meta.segments[0] |
| Yol derinliğini almak | size(meta.segments) |
| Yol belirli bir segment içeriyor mu kontrolü | "admin" in meta.segments |
// İlk segmenti al (çoğunlukla dil kodu)
meta.segments[0]
// Yol derinliğini kontrol et
size(meta.segments) > 2 ? "deep" : "shallow"
// Yönetici bölümünde miyiz kontrol et
"admin" in meta.segments ? "admin mode" : "public mode"
// Yedek: Parametre bağlı değilse segmenti kullan
has(meta.params.lang) ? meta.params.lang : meta.segments[0]
meta nesnesi, geçerli istekle ilgili 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> | Rota deseninden çıkarılan URL parametreleri | |
meta.segments | string[] | Segmentlere ayrılmış URL yolu | |
meta.docId | string \\ | null | Geçerli belgenin UUID'si (yeni belgeler için null) | |
meta.title | string | Geçerli belgenin başlığı |
Yerel ayar kodu BCP 47 biçimini (dil-bölge) izler:
// Sağdan sola dillere göre yerel ayarı kontrol et
meta.locale == "ar-SA" || meta.locale == "he-IL" ? "rtl" : "ltr"
// Yalnızca dil bölümünü al
meta.locale.split("-")[0] // Desteklenmez - bunun yerine meta.params.lang kullanın
Rota parametreleri her zaman stringtir. CMS, değerlendirmeden önce bunları bağlanan şemalara göre doğrular:
// Adlandırılmış parametreye eriş
meta.params.lang // "ko"
meta.params.country // "us"
meta.params.slug // "welcome-post"
// Parametre var mı kontrol et
has(meta.params.category) // true/false
// Belge getirmede kullanın
documents.get("greeting", meta.params.lang)
documents.ref("airports").get(meta.params.code)
Ham URL segmentleri bir dizi olarak:
// İndekse göre eriş (0 tabanlı)
meta.segments[0] // İlk segment
meta.segments[1] // İkinci segment
// Uzunluğu kontrol et
size(meta.segments) // Segment sayısı
// Üyelik kontrolü
"products" in meta.segments // Yolda "products" var mı?
Geçerli belgenin UUID'si, kendine referans veren betikler için kullanışlıdır:
// Yalnızca mevcut belgeleri düzenlerken kullanılabilir
meta.docId != null ? "editing" : "creating new"
// Koşullu mantıkta kullan
meta.docId != null ? documents.get("article", meta.docId).status : "draft"
Geçerli belgenin başlığı:
// Görüntülemede kullan
"Editing: " + meta.title
// Başlığa göre koşul
meta.title.contains("Draft") ? "work in progress" : "published"
Şemanın bilindiği ancak tanımlayıcının dinamik olduğu durumlarda daha temiz sözdizimi:
// Geleneksel yaklaşım
documents.get("airports", meta.params.code).name
// ref() kullanımı - şema dinamik tanımlayıcıdan ayrı
documents.ref("airports").get(meta.params.code).name
Her ikisi de eşdeğerdir, ancak ref() dinamik kısmı daha net hale getirir.
documents.get("schema", "identifier") // Tek bir belge getir
documents.get("schema", "id").fieldName // Belirli bir alanı getir
documents.find("schema") // Tüm belgeleri getir
documents.find("schema", { "where": {...}}) // Filtrelenmiş sorgu
documents.ref("schema").get(identifier) // Zincirleme arama
meta.locale // "en-US", "ar-SA" vb.
meta.params.xyz // "xyz" adlı URL parametresi
meta.segments // URL yolu dizi olarak: ["articles", "intro"]
meta.segments[0] // İlk yol segmenti
meta.docId // Geçerli belge kimliği (veya null)
meta.title // Geçerli belgenin başlığı
// Karşılaştırma
== != < <= > >=
// Mantık
&& || !
// Üçlü (if-else)
condition ? valueIfTrue : valueIfFalse
// Üyelik
"value" in listOrMap
size(list) // Öğeleri say
size(string) // String uzunluğunu al
"text".startsWith("te") // true
"text".endsWith("xt") // true
"text".contains("ex") // true
has(object.property) // Özellik var mı kontrol et
Bir şeyler ters giderse şu uyarılardan birini görürsünüz:
| Hata | Anlamı |
|---|---|
SYNTAX_ERROR | Betiğinizde yazım hatası var (eksik tırnak, yanlış operatör) |
TYPE_ERROR | Birbiriyle çalışmayan türleri karıştırıyorsunuz |
RUNTIME_ERROR | Betik çalıştı ancak bir sorunla karşılaştı (tanımsız değişken) |
FETCH_LIMIT_EXCEEDED | Çok fazla belge getiriyorsunuz (en fazla 50) |
TIMEOUT | Betik çok uzun sürdü (en fazla 5 saniye) |
AST_DEPTH_EXCEEDED | İfade çok derin bir yapıya sahip (maksimum derinlik: 50) |
SCRIPT_TOO_LONG | Betik 5000 karakter sınırını aşıyor |
CEL motoru genişletilebilir olacak şekilde tasarlanmıştır. Gelecekte planlanan yetenekler şunları içerir:
// Gelecekte: MCP aracılığıyla harici servisleri ç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, geriye dönük uyumluluğu koruyarak kayıtlı fonksiyon sistemi aracılığıyla eklenecektir.
documents. veya meta. yazarak düzenleyicinin kullanılabilir seçenekleri göstermesini sağlayındocuments.get("schema", "id") ile test edin, sonra .fieldName ekleyin!= null ? ... : ... ile yedek değer ekleyindocuments.get() veya documents.find() çağrısı 50 getirme sınırına sayılırmeta.params.category'yi kullanmadan önce has(meta.params.category) ile kontrol edinBu rehber, /{lang}/landingPage adresinden erişilebilen çok dilli bir açılış sayfası oluşturur.
CMS yönetiminde greeting adlı özel bir şema oluşturun:
{
"name": "greeting",
"fields": [
{ "name": "code", "type": "string", "required": true },
{ "name": "headline", "type": "string", "required": true },
{ "name": "subheadline"
Her dil için belgeler oluşturun:
Belge: greeting / ko
{
"code": "ko",
"headline": "환영합니다",
"subheadline": "우리 플랫폼에 오신 것을 환영합니다",
"ctaText": "시작하기",
"ctaUrl": "/ko/get-started"
}
Belge: greeting / en
{
"code": "en",
"headline": "Welcome",
"subheadline": "Welcome to our platform",
"ctaText": "Get Started",
"ctaUrl": "/en/get-started"
}
Belge: greeting / ja
{
"code": "ja",
"headline": "ようこそ",
"subheadline": "私たちのプラットフォームへようこそ",
"ctaText": "始める",
"ctaUrl": "/ja/get-started"
}
Aşağıdaki yapılandırmaya sahip bir rota oluşturun:
/{lang}/landingPage/{lang}/landingPage {
"lang": "language"
}
Rotaya bir hero bloğu ekleyin ve her alan için şu CEL betiklerini kullanın:
Başlık alanı:
documents.get("greeting", meta.params.lang).headline
Alt başlık alanı:
documents.get("greeting", meta.params.lang).subheadline
CTA Metni alanı:
documents.get("greeting", meta.params.lang).ctaText
CTA URL alanı:
documents.get("greeting", meta.params.lang).ctaUrl
Next.js uygulamanızda yakala-tüm rotası oluşturun:
// app/[...slug]/page.tsx
import { getCmsClient } from '@repo/renderer';
interface PageProps {
params: { slug: string[] };
}
export default async function Page({ params }: PageProps) {
Bu URL'leri ziyaret ederek yerelleştirilmiş içeriği görün:
| URL | Beklenen Başlık |
|---|---|
/ko/landingPage | 환영합니다 |
/en/landingPage | Welcome |
/ja/landingPage | ようこそ |
Bir kullanıcı /ko/landingPage adresini ziyaret ettiğinde:
/{lang}/landingPage desenini eşleştirirmeta.params.lang = "ko"language şemasında bulunduğunu doğrulardocuments.get("greeting", meta.params.lang) gibi betikler Korece içeriğe çözülürinterface CelMeta {
/** Geçerli yerel ayar kodu (örn. 'en-US') */
locale: string;
/** URL'den çıkarılan rota parametreleri */
params: Record<string, string>;
/** URL yolu segmentleri */
segments: string[];
/** Mevcut belge kimliği (varsa) */
extractParams fonksiyonu URL yollarını şöyle işler:
Pattern: /{country}/{lang}/products
Path: /us/en/products
Algorithm:
1. Her ikisini normalleştir (sondaki eğik çizgileri kaldır)
2. Segmentlere ayır: ["us", "en", "products"] ve ["{country}", "{lang}", "products"
// Basit bağlama (arama için "code" alanını kullanır)
{ "lang": "language" }
// Ayrıntılı bağlama (özel slug alanı)
{
"lang": {
"schemaName": "language",
"slugField": "code"
},
"slug": {
"schemaName": "article",
"slugField": "slug"
}
documents.get(schema, identifier) ile getirirken öncelik sırası:
id ile getircontent.code alanını kontrol etcontent.slug alanını kontrol ettitle alanını kontrol etBu sayede belgeler, herhangi bir benzersiz tanımlayıcıyla esnek şekilde referans alınabilir.