profound-logoProfound CMS
⌘K
Admin
Theme
DocsTutorialBlogPhilosophy
DocsTutorialBlogPhilosophy

Hybrid

ניתוב פרמטריסוגי רכיביםSetup server sent events (SSE) content refetchInstall Profound CMS as a proxyכתיבת סקריפטים בבונה התבניותProject Scaffoldingספריית המדיה

ללא ראש

התחלה מהירהSplit Screen JSON Component Builder with LLMComponent Zod Pull

ממשק REST

סקירת REST APIgetחיבור-אתר-ל-API-של-CMSgetGET /routesgetGET /routegetקבלת בלוקיםgetהשגת-בלוקים-עם-מטמון-CELgetGET /blocks/generatedgetקבל רכיביםgetGET /components/{name}getGET /dataset/{schema_name}getGET /content-changes (SSE)patchPATCH /dataset/{schema_name}postתרגום פוסטpatchPATCH /translationsgetGET /usagepostפוסט-CSVpatchPATCH /csv
All Systems Operational
Powered Byprofound-logo
Theme

כתיבת סקריפטים בבונה התבניות

מדריך מעשי לכתיבת ביטויי CEL במערכת ניהול התוכן.

מדריך מעשי לכתיבת ביטויי CEL במערכת ניהול התוכן.


כיצד CEL פועל

CEL (שפת ביטויים נפוצה) היא שפת סקריפטים קלת־משקל המובנית במערכת ניהול התוכן שלנו. היא מאפשרת לכתוב ביטויים דינמיים השואבים נתונים ממסמכים, קוראים פרמטרים מכתובות URL ומחשבים ערכים בזמן הריצה.

זה מה שקורה כאשר סקריפט CEL מופעל:

Your Script                    The Engine                     Result
    |                              |                              |
    v                              v                              v
documents.get("article", "intro") --> Fetches from database --> { headline: "Welcome", body: "..." }
         .headline                --> Extracts the field    --> "Welcome"

חשבו על CEL כשפת שאילתות לקריאה בלבד. היא אינה יכולה לשנות דבר במסד הנתונים — היא רק קוראת נתונים ומחזירה תוצאה מחושבת. לכן בטוח להשתמש בה בכל מקום במערכת ניהול התוכן.


אבני הבניין

לכל ביטוי CEL יש גישה לשלושה דברים:

אובייקטמהודוגמה
documentsאחזור כל מסמך ממערכת ניהול התוכןdocuments.get("country", "us")
metaמידע על הבקשה הנוכחית (אזור, פרמטרים של כתובת URL)meta.locale, meta.params.slug
schemaהגדרות השדות של המסמך הנוכחיschema.fields

הפניה עצמית באמצעות doc

בעת כתיבת ביטויי CEL בתוך עורך מסמכים, ניתן לגשת לערכי השדות של המסמך הנוכחי באמצעות האובייקט doc. כך ניתן ליצור שדות מחושבים והפניות בין שדות.

// Access current document's price field
doc.price

// Calculate total from current document fields
doc.price * doc.quantity

// Conditional based on current document status
doc.status == "published" ? doc.title : "Draft: " + doc.title

האובייקט doc מכיל את כל ערכי השדות של המסמך הנערך. הוא שימושי עבור:

  • שדות מחושבים (לדוגמה, doc.price * doc.quantity)
  • לוגיקת תצוגה מותנית המבוססת על מצב המסמך
  • ביטויים בסגנון אימות

אחזור מסמכים

התכונה החזקה ביותר של CEL היא היכולת לאחזר מסמכים מכל מקום במערכת ניהול התוכן.

קבלת מסמך יחיד

תחביר: documents.get(schemaName, identifier)

נניח שיש לכם מסמך article המאוחסן עם המזהה "welcome-post":

// Stored in the CMS as: 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")

אחזור הכותרת בלבד:

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)

// Get all countries
documents.find("country")
// Get countries with a filter
documents.find("country", { "where": { "code": "us" } })

תרגומים

CEL תומכת באחזור תוכן מתורגם של מסמכים בשתי דרכים: תרגום אוטומטי המבוסס על האזור, וחיפוש תרגום מפורש.

תרגום אוטומטי באמצעות meta.locale

כאשר meta.locale מוגדר (למשל מפרמטרים של נתיב או מהעדפות המשתמש), documents.get() ממזגת אוטומטית תוכן מתורגם:

// If meta.locale is "fr", returns French translation merged with base document
documents.get("greeting", "welcome").headline

אופן הפעולה:

  1. אחזור תוכן המסמך הבסיסי
  2. אם meta.locale אינו "en" או "en-US", חיפוש התרגום בטבלת translations
  3. מיזוג השדות המתורגמים מעל תוכן הבסיס: { ...baseContent, ...translatedContent }

משמעות הדבר היא ששדות מתורגמים מחליפים את שדות הבסיס, ואילו שדות שלא תורגמו משתמשים בערכי המסמך הבסיסי.

תרגום מפורש באמצעות documents.translated()

כאשר יש צורך לאחזר תרגום מסוים בלי קשר לאזור הנוכחי:

תחביר: documents.translated(schemaName, identifier, locale)

// Always fetch Spanish translation
documents.translated("greeting", "welcome", "es").headline

// Fetch translation based on URL parameter
documents.translated("product", meta.params.id, meta.params.lang).description

// Compare translations
documents.translated("article", "intro", "en").title + " / " + documents.translated("article", "intro", "fr").title

דוגמאות מהעולם האמיתי

דוגמה 1: כותרת בלוק Hero ממסמך אחר

יש לכם hero-block שאמור להציג כותרת שנלקחה ממסמך article.

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

תוצאה: ה־hero מציג את הכותרת מהמסמך.

דוגמה 2: שם מדינה לפי קוד

בעת בניית דף בכתובת /countries/[code], ניתן להציג את השם המלא של המדינה:

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

דוגמה 3: תוכן מותנה לפי אזור

meta.locale == "ar-SA" ? "Welcome, everyone" : "Welcome"

דוגמה 4: חיפושי מסמכים משורשרים

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

דוגמה 5: ערכי ברירת מחדל

documents.get("article", meta.params.slug) != null
  ? documents.get("article", meta.params.slug).headline
  : "Article Not Found"

דוגמה 6: עבודה עם רשימות

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

נתיבים פרמטריים ו־meta.params

נתיבים פרמטריים הם המפתח לבניית דפים דינמיים ומותאמים לשפה. כאשר מגדירים תבנית נתיב כמו /{lang}/landingPage, מערכת ניהול התוכן מחלצת את הפרמטרים מכתובת ה־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"
  }
}

הקישור מורה למערכת:

  1. לחלץ את המקטע lang מכתובת ה־URL
  2. לאמת אותו מול סכמת language
  3. אם הוא תקין, להפוך את המסמך המלא לזמין בפרמטרים שנפתרו

דוגמה: דף נחיתה לפי שפה

documents.get("greeting", meta.params.lang).headline
כתובת URLmeta.params.langתוצאה
/ko/landingPage"ko""Welcome"
/en/landingPage"en""Welcome"
/ja/landingPage"ja""Welcome"

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 ? "deep" : "shallow"
"admin" in meta.segments ? "admin mode" : "public mode"
has(meta.params.lang) ? meta.params.lang : meta.segments[0]

תיעוד מלא של אובייקט meta

מאפייןסוגתיאור
meta.localestringקוד האזור הנוכחי, למשל "en-US", "ko-KR", "ar-SA"
meta.paramsRecord<string, string>פרמטרים של הנתיב שחולצו מתבנית כתובת ה־URL
meta.segmentsstring[]נתיב כתובת ה־URL המחולק למקטעים
meta.docIdstring \| nullמזהה ה־UUID של המסמך הנוכחי
meta.titlestringכותרת המסמך הנוכחי

meta.locale

קוד האזור פועל לפי תבנית BCP 47:

meta.locale == "ar-SA" || meta.locale == "he-IL" ? "rtl" : "ltr"
meta.locale.split("-")[0]  // Not supported - use meta.params.lang instead

meta.params

פרמטרים של נתיב הם תמיד מחרוזות. מערכת ניהול התוכן מאמתת אותם מול הסכמות המקושרות לפני ההערכה:

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.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() — חיפושים משורשרים

כאשר הסכמה ידועה אך המזהה דינמי, ניתן להשתמש בתחביר נקי יותר:

documents.get("airports", meta.params.code).name
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הסקריפט חורג ממגבלת 5,000 התווים

יכולות הרחבה ויכולות עתידיות

מנוע CEL תוכנן להרחבה. היכולות המתוכננות לעתיד כוללות:

מתוכנן: שילוב שרת MCP

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"])

יכולות אלה יתווספו באמצעות מערכת הפונקציות הרשומות, תוך שמירה על תאימות לאחור עם סקריפטים קיימים.


טיפים

  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 להפניות עצמיות — גישה לשדות המסמך הנוכחי בתוך ביטויים מחושבים

הפניות ממסמך למסמך

סעיף זה עוסק בדפוסים מתקדמים לקישור מסמכים ולבניית מבני תוכן יחסיים.

דפוס הפניה בסיסי

הצורה הפשוטה ביותר: מסמך אחד מפנה למסמך אחר באמצעות מזהה.

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

מעקב אחר תלויות

כל קריאה ל־documents.get(), ל־documents.find() ול־documents.ref().get() נרשמת לצורך ביטול מטמון. כאשר מסמך שאליו מפנים משתנה, מערכת ניהול התוכן יודעת אילו ביטויי CEL יש להעריך מחדש.

התלויות הנרשמות כוללות:

  • get: schema:identifier — תלות במסמך מסוים
  • ref: schema:identifier — זהה ל־get, באמצעות תחביר משורשר
  • query: schema:* — תלות ברמת הסכמה, כלומר כל מסמך בסכמה

שיטות עבודה מומלצות להפניות

  1. צמצמו את עומק השרשרת — כל רמה מוסיפה זמן ומספר אחזורים
  2. שמרו תוצאות ביניים במטמון — אם צריך את אותו ערך מקונן פעמיים, אחזרו את האב פעם אחת
  3. השתמשו בבדיקות null — הפניות עלולות להיכשל אם מסמכים נמחקו
  4. העדיפו קודים על פני UUID — קודים קריאים יותר בביטויים ויציבים בין סביבות
  5. שימו לב למגבלות האחזור — שרשראות מורכבות עלולות להגיע במהירות למגבלת 50 האחזורי́ם

נספח א: דוגמה מלאה לנתיב פרמטרי

מדריך זה יוצר דף נחיתה רב־לשוני הזמין בכתובת /{lang}/landingPage.

שלב 1: יצירת סכמת מסמך Greeting

בממשק הניהול של מערכת ניהול התוכן, צרו סכמה מותאמת אישית בשם greeting.

שלב 2: יצירת מסמכי Greeting

צרו מסמך עבור כל שפה.

שלב 3: יצירת הדף

צרו דף עם התצורה הבאה:

  • נתיב/תבנית: /{lang}/landingPage
  • מצב: פעיל
  • מיפויי מקטעים דינמיים: מיפוי lang אל רכיב language

שלב 4: הוספת בלוקים עם סקריפטי CEL

הוסיפו בלוק hero לנתיב עם הסקריפטים הבאים:

documents.get("greeting", meta.params.lang).headline
documents.get("greeting", meta.params.lang).subheadline
documents.get("greeting", meta.params.lang).ctaText
documents.get("greeting", meta.params.lang).ctaUrl

שלב 5: שימוש ב־Next.js

הוסיפו נתיב catch-all. ParametricRoutePage פותר את הדף, מחלץ את meta.params מכתובת ה־URL, מעריך את קישורי CEL בצד השרת ומרנדר כל בלוק באמצעות הרישום שלכם.

שלב 6: בדיקת הנתיבים

בקרו בכתובות הבאות כדי לראות תוכן מותאם לשפה:

כתובת URLכותרת צפויה
/ko/landingPage환영
/en/landingPageברוכים הבאים
/ja/landingPageいらっしゃいませ

נספח ב: תיעוד טכני

ממשק CelMeta (TypeScript)

interface CelMeta {
  /** Current locale code (e.g., 'en-US') */
  locale: string;
  /** Route parameters extracted from URL */
  params: Record<string, string>;
  /** URL path segments */
  segments: string[];
  /** Current document ID (if editing existing document) */
  docId: string | null;
  /** Current document title */
  title: string;
}

אלגוריתם חילוץ פרמטרים

הפונקציה extractParams מעבדת נתיבי URL:

Pattern: /{country}/{lang}/products
Path:    /us/en/products

Algorithm:
1. Normalize both (remove trailing slashes)
2. Split into segments: ["us", "en", "products"] and ["{country}", "{lang}", "products"]
3. Match segment counts (must be equal)
4. For each segment pair:
   - If pattern starts with : or {}, extract as param
   - Otherwise, must match exactly
5. Return: { country: "us", lang: "en" }

תבניות קישור פרמטרים נתמכות

{ "lang": "language" }

{
  "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›