CMS में CEL एक्सप्रेशन लिखने की एक व्यावहारिक मार्गदर्शिका।
CMS में CEL एक्सप्रेशन लिखने की एक व्यावहारिक मार्गदर्शिका।
CEL (Common Expression Language) हमारे CMS में निर्मित एक हल्की स्क्रिप्टिंग भाषा है। इससे आप ऐसे डायनेमिक एक्सप्रेशन लिख सकते हैं जो दस्तावेज़ों से डेटा प्राप्त करें, URL पैरामीटर पढ़ें और तुरंत मानों की गणना करें।
CEL स्क्रिप्ट चलने पर यह होता है:
आपकी स्क्रिप्ट इंजन परिणाम
documents.get("article", "intro") --> डेटाबेस से प्राप्त करता है --> { headline: "Welcome", body: "..." }
.headline --> फ़ील्ड निकालता है --> "Welcome"
CEL को केवल-पठन क्वेरी भाषा समझें। यह डेटाबेस में कुछ बदल नहीं सकती—यह केवल डेटा पढ़कर गणना किया हुआ परिणाम लौटाती है। इसलिए CMS में इसका उपयोग सुरक्षित है।
हर CEL एक्सप्रेशन को तीन चीज़ों तक पहुँच प्राप्त होती है:
| ऑब्जेक्ट | यह क्या है | उदाहरण |
|---|---|---|
documents | CMS से कोई भी दस्तावेज़ प्राप्त करता है | documents.get("country", "us") |
meta | वर्तमान अनुरोध की जानकारी (लोकेल, URL पैरामीटर) | meta.locale, meta.params.slug |
schema | वर्तमान दस्तावेज़ की फ़ील्ड परिभाषाएँ | schema.fields |
doc से स्वयं-संदर्भदस्तावेज़ संपादक के भीतर CEL एक्सप्रेशन लिखते समय, doc ऑब्जेक्ट की सहायता से वर्तमान दस्तावेज़ के फ़ील्ड मानों तक पहुँच सकते हैं। इससे गणना किए गए फ़ील्ड और विभिन्न फ़ील्ड के बीच संदर्भ बनाना संभव होता है।
// वर्तमान दस्तावेज़ का price फ़ील्ड
doc.price
// वर्तमान दस्तावेज़ के फ़ील्ड से कुल की गणना
doc.price * doc.quantity
// वर्तमान दस्तावेज़ की स्थिति के आधार पर शर्त
doc.status == "published" ? doc.title : "Draft: " + doc.title
doc ऑब्जेक्ट में संपादित दस्तावेज़ के सभी फ़ील्ड मान होते हैं। यह निम्न कार्यों के लिए उपयोगी है:
doc.price * doc.quantityCEL की सबसे शक्तिशाली सुविधा CMS में कहीं से भी दस्तावेज़ प्राप्त करना है।
सिंटैक्स: documents.get(schemaName, identifier)
मान लें कि आपके पास "welcome-post" पहचानकर्ता वाला article दस्तावेज़ है:
// CMS में संग्रहीत: article / welcome-post
{
"headline": "Welcome to Our Platform",
"author": "Sarah Chen",
"body": "We're excited to announce...",
"tags": ["announcement", "news"]
}
पूरा दस्तावेज़ प्राप्त करने के लिए:
documents.get("article", "welcome-post")
परिणाम: वही पूरा दस्तावेज़ लौटता है।
केवल headline प्राप्त करने के लिए:
documents.get("article", "welcome-post").headline
परिणाम: "Welcome to Our Platform"
लेखक प्राप्त करने के लिए:
documents.get("article", "welcome-post").author
परिणाम: "Sarah Chen"
जब आपके पृष्ठ में डायनेमिक रूट, जैसे /articles/[slug], हों, तब URL पैरामीटर प्राप्त करने और सही दस्तावेज़ लाने के लिए meta.params का उपयोग करें।
यदि कोई व्यक्ति /articles/welcome-post पर जाता है:
documents.get("article", meta.params.slug).headline
परिणाम: "Welcome to Our Platform"
इसी प्रकार डायनेमिक पृष्ठ बनाए जाते हैं—एक ही CEL स्क्रिप्ट किसी भी लेख के लिए काम करती है और URL में मौजूद slug का उपयोग करती है।
सिंटैक्स: documents.find(schemaName) या documents.find(schemaName, filter)
// सभी देश प्राप्त करें
documents.find("country")
परिणाम: देशों की एक सूची।
// फ़िल्टर के साथ देश प्राप्त करें
documents.find("country", { "where": { "code": "us" } })
यह केवल फ़िल्टर से मेल खाने वाले दस्तावेज़ लौटाता है।
CEL अनुवादित दस्तावेज़ सामग्री प्राप्त करने के दो तरीके प्रदान करता है: लोकेल-आधारित स्वचालित अनुवाद और स्पष्ट अनुवाद खोज।
meta.locale के माध्यम से स्वचालित अनुवादजब meta.locale सेट हो, जैसे रूट पैरामीटर या उपयोगकर्ता की पसंद से, तो documents.get() अनुवादित सामग्री को स्वतः मिला देता है:
// यदि meta.locale "fr" है, तो मूल दस्तावेज़ के साथ फ़्रेंच अनुवाद मिलाकर लौटाता है
documents.get("greeting", "welcome").headline
यह इस प्रकार काम करता है:
meta.locale "en" या "en-US" नहीं है, तो translations तालिका में अनुवाद खोजा जाता है।{ ...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
यदि hero-block को article दस्तावेज़ से headline दिखानी हो, तो उसके title फ़ील्ड में यह CEL स्क्रिप्ट लिखें:
documents.get("article", "homepage-hero").headline
परिणाम: Hero में लेख की headline प्रदर्शित होगी।
/countries/[code] पृष्ठ पर पूरा देश का नाम दिखाने के लिए:
documents.get("country", meta.params.code).name
/countries/us पर meta.params.code का मान "us" और परिणाम "United States" होगा।
meta.locale == "ar-SA" ? "Welcome, everyone" : "Welcome"
यदि लोकेल "ar-SA" है तो "Welcome, everyone", अन्यथा "Welcome" लौटेगा।
documents.get("country", documents.get("article", "us-news").countryCode).name
पहले लेख प्राप्त होता है, फिर उसका countryCode निकाला जाता है, उसके आधार पर देश प्राप्त होता है और अंत में .name से देश का नाम लिया जाता है।
documents.get("article", meta.params.slug) != null
? documents.get("article", meta.params.slug).headline
: "Article Not Found"
यदि दस्तावेज़ मौजूद न हो तो वैकल्पिक मान लौटाया जाता है। किसी फ़ील्ड के लिए भी इसी प्रकार जाँच की जा सकती है।
"featured" in documents.get("article", "welcome-post").tags
लेख में featured टैग होने पर true लौटता है।
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 को बताती है:
lang खंड निकालें।language स्कीमा के विरुद्ध सत्यापित करें।documents.get("greeting", meta.params.lang).headline
/ko/landingPage, /en/landingPage और /ja/landingPage पर यही स्क्रिप्ट संबंधित भाषा का greeting दस्तावेज़ प्राप्त करेगी।
{
"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 + " from " + documents.get("country", meta.params.country).name
CMS पैरामीटरों को क्रमिक रूप से सत्यापित करता है: पहले country, फिर lang, और आवश्यकता होने पर यह भी जाँचता है कि lang, country.languages[] में मौजूद है।
meta.segments — कच्चे URL पथ तक पहुँचmeta.segments कच्चे URL पथ को एक array के रूप में देता है। नामित पैरामीटर के बिना स्थान-आधारित पहुँच के लिए यह उपयोगी है।
| URL पथ | meta.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 ? "deep" : "shallow"
// admin अनुभाग जाँचें
"admin" in meta.segments ? "admin mode" : "public mode"
// यदि पैरामीटर बाउंड न हो तो segment का उपयोग करें
has(meta.params.lang) ? meta.params.lang : meta.segments[0]
meta ऑब्जेक्ट संदर्भmeta ऑब्जेक्ट में वर्तमान अनुरोध का पूरा संदर्भ होता है:
| प्रॉपर्टी | प्रकार | विवरण |
|---|---|---|
meta.locale | string | वर्तमान लोकेल कोड, जैसे "en-US", "ko-KR", "ar-SA" |
meta.params | Record<string, string> | URL पैटर्न से निकाले गए रूट पैरामीटर |
meta.segments | string[] | खंडों में विभाजित URL पथ |
meta.docId | string | null | वर्तमान दस्तावेज़ UUID; नए दस्तावेज़ के लिए null |
meta.title | string | वर्तमान दस्तावेज़ का शीर्षक |
meta.localeलोकेल कोड BCP 47 प्रारूप का पालन करता है:
// RTL भाषाओं की जाँच
meta.locale == "ar-SA" || meta.locale == "he-IL" ? "rtl" : "ltr"
// केवल भाषा वाला भाग प्राप्त करें
meta.locale.split("-")[0] // समर्थित नहीं—इसके बजाय meta.params.lang का उपयोग करें
meta.paramsरूट पैरामीटर हमेशा string होते हैं। मूल्यांकन से पहले CMS उन्हें संबंधित स्कीमा के विरुद्ध सत्यापित करता है:
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.docIdवर्तमान दस्तावेज़ का UUID, जो स्वयं-संदर्भित स्क्रिप्ट में उपयोगी है:
meta.docId != null ? "editing" : "creating new"
meta.docId != null ? documents.get("article", meta.docId).status : "draft"
meta.title"Editing: " + meta.title
meta.title.contains("Draft") ? "work in progress" : "published"
documents.ref() — क्रमबद्ध खोजजब स्कीमा ज्ञात हो लेकिन पहचानकर्ता डायनेमिक हो, तो साफ़ सिंटैक्स के लिए 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
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")
यदि कुछ गलत होता है, तो इनमें से कोई संदेश दिखाई देगा:
| त्रुटि | अर्थ |
|---|---|
SYNTAX_ERROR | स्क्रिप्ट में टाइपो, गायब उद्धरण या गलत ऑपरेटर |
TYPE_ERROR | असंगत प्रकारों को एक साथ मिलाया गया है |
RUNTIME_ERROR | स्क्रिप्ट चली, लेकिन किसी समस्या से टकराई |
FETCH_LIMIT_EXCEEDED | बहुत अधिक दस्तावेज़ प्राप्त किए जा रहे हैं; अधिकतम 50 |
TIMEOUT | स्क्रिप्ट ने बहुत समय लिया; अधिकतम 5 सेकंड |
AST_DEPTH_EXCEEDED | एक्सप्रेशन बहुत अधिक नेस्टेड है; अधिकतम गहराई 50 |
SCRIPT_TOO_LONG | स्क्रिप्ट 5000 वर्णों की सीमा से अधिक है |
CEL इंजन को विस्तार योग्य बनाया गया है। भविष्य में निम्न क्षमताएँ जोड़ी जाने की योजना है:
mcp.translate(meta.params.text, "en", meta.params.lang)
mcp.analyze(documents.get("article", meta.params.id).body)
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"])
इन क्षमताओं को पंजीकृत फ़ंक्शन प्रणाली के माध्यम से जोड़ा जाएगा और मौजूदा स्क्रिप्ट के साथ पिछली संगतता बनी रहेगी।
documents. या meta. टाइप करने पर संपादक उपलब्ध विकल्प दिखाएगा।documents.get("schema", "id") जाँचें, फिर .fieldName जोड़ें।!= null ? ... : ... से fallback दें।documents.get() या documents.find() 50-fetch सीमा में गिना जाता है।meta.segments के बजाय meta.params को प्राथमिकता दें — नामित पैरामीटर सत्यापित और अधिक विश्वसनीय होते हैं।has() का उपयोग करें।documents.ref() का उपयोग करें।doc.fieldName का उपयोग करें।यह भाग दस्तावेज़ों को जोड़ने और संबंधपरक सामग्री संरचनाएँ बनाने के उन्नत तरीकों को समझाता है।
एक दस्तावेज़ दूसरे को पहचानकर्ता के माध्यम से संदर्भित करता है:
documents.get("author", documents.get("article", "intro").authorId).name
documents.ref() से क्रमबद्ध खोजdocuments.get("country", documents.get("airport", meta.params.code).countryCode).name
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
दस्तावेज़ किसी दूसरे दस्तावेज़ की ID या semantic code रख सकते हैं। वर्तमान दस्तावेज़ के मानों पर आधारित गणना किए गए फ़ील्ड के लिए doc का उपयोग करें:
documents.get("category", doc.categoryId).description
documents.get("shipping-rates", doc.originCountry).baseRate * doc.weight
द्विदिश संदर्भों में fetch सीमा का ध्यान रखें। अलग-अलग स्कीमा वाले polymorphic संदर्भों में sourceType के आधार पर सशर्त खोज करें।
हर documents.get(), documents.find() और documents.ref().get() कॉल cache invalidation के लिए ट्रैक की जाती है। संदर्भित दस्तावेज़ बदलने पर CMS जानता है कि किन CEL एक्सप्रेशन का पुनर्मूल्यांकन करना है।
ट्रैक की जाने वाली निर्भरताएँ:
schema:identifierschema:identifierschema:*यह walkthrough /{lang}/landingPage पर उपलब्ध बहुभाषी landing page बनाता है।
CMS प्रशासन में greeting नाम का custom schema बनाएँ:
{
"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" }
]
}
प्रत्येक भाषा के लिए दस्तावेज़ बनाएँ: greeting/ko, greeting/en और greeting/ja। प्रत्येक में code, headline, subheadline, ctaText और ctaUrl फ़ील्ड रखें।
निम्न कॉन्फ़िगरेशन वाला पृष्ठ बनाएँ:
/{lang}/landingPagelang को language component से मैप करें{
"lang": "language"
}
// Headline
documents.get("greeting", meta.params.lang).headline
// Subheadline
documents.get("greeting", meta.params.lang).subheadline
// CTA टेक्स्ट
documents.get("greeting", meta.params.lang).ctaText
// CTA URL
documents.get("greeting", meta.params.lang).ctaUrl
एक catch-all route जोड़ें। ParametricRoutePage पृष्ठ को resolve करता है, URL से meta.params निकालता है, CEL bindings का सर्वर-साइड मूल्यांकन करता है और registry के माध्यम से प्रत्येक ब्लॉक render करता है।
// 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 पर जाएँ:
| URL | अपेक्षित headline |
|---|---|
/ko/landingPage | 환영 |
/en/landingPage | Welcome |
/ja/landingPage | いらっしゃいませ |
जब उपयोगकर्ता /ko/landingPage पर जाता है:
/{lang}/landingPage पैटर्न से रूट का मिलान करता है।meta.params.lang = "ko" निकाला जाता है।"ko", language स्कीमा में मौजूद है।documents.get("greeting", meta.params.lang) जैसी स्क्रिप्ट कोरियाई सामग्री में resolve होती हैं।interface CelMeta {
/** वर्तमान लोकेल कोड, जैसे 'en-US' */
locale: string;
/** URL से निकाले गए रूट पैरामीटर */
params: Record<string, string>;
/** URL पथ के खंड */
segments: string[];
/** वर्तमान दस्तावेज़ ID */
docId: string | null;
/** वर्तमान दस्तावेज़ का शीर्षक */
title: string;
}
extractParams फ़ंक्शन URL पथों को संसाधित करता है:
Pattern: /{country}/{lang}/products
Path: /us/en/products
Algorithm:
1. दोनों को सामान्य करें (अंतिम slash हटाएँ)
2. segments में विभाजित करें
3. segments की संख्या समान होनी चाहिए
4. प्रत्येक segment जोड़ी के लिए:
- यदि पैटर्न : या {} से शुरू होता है, तो उसे पैरामीटर के रूप में निकालें
- अन्यथा, बिल्कुल समान मिलान आवश्यक है
5. लौटाएँ: { country: "us", lang: "en" }
// सरल binding (lookup के लिए "code" फ़ील्ड)
{ "lang": "language" }
// विस्तृत binding (custom slug फ़ील्ड)
{
"lang": {
"schemaName": "language",
"slugField": "code"
},
"slug": {
"schemaName": "article",
"slugField": "slug"
}
}
documents.get(schema, identifier) के माध्यम से प्राप्त करते समय:
id से प्राप्त करें।content.code जाँचें।content.slug जाँचें।title फ़ील्ड जाँचें।इससे किसी भी विशिष्ट पहचानकर्ता द्वारा लचीले दस्तावेज़ संदर्भ संभव होते हैं।