דלג לתוכן הראשי
//מדריך לבניית מערכת ניהול תוכן - עודד בהירי

ככה בונים אתר בקוד — מהיר ויפה, בלי תקרה — שאתה עורך לבד, בלי מפתח ובלי לחכות. הסוד נקרא Headless CMS. במדריך הזה אני מראה בדיוק איך — צעד אחרי צעד, עם פרומפטים מוכנים להעתקה ל-Claude או ל-Codex.

  • לבעלי עסקים — מה זה ולמה זה עדיף
  • למפתחים — כל הקוד, מוכן להעתקה
FIG.01 — SANITY STUDIO1:1
your-site.com/studio
מסך עריכת מוצר בעברית בלוח הניהול של Sanity Studio — שם, מחיר וסטטוס
OWN YOUR SITE

קודם, הבעיה

בנית אתר ב-AI — מהמם, מתקדם. ואז ניסית להחליף תמונה לבד, ונתקעת. זה לא אתה: אתר מתקדם בנוי בקוד, וקוד צריך מתכנת כדי לגעת בו. כל שינוי קטן חוזר אליו, עולה כסף, ולוקח זמן.

הפתרון הרגיל? WordPress או Wix — שם כן עורכים לבד, אבל יוצא מוגבל, איטי, ונראה כמו כל אתר אחר. עד עכשיו היית צריך לבחור בין השניים. כבר לא.

הרעיון: מפרידים תוכן מקוד

Headless CMS זה רעיון פשוט: מפרידים את התוכן מהקוד. הקוד נשאר במקום — מהיר, מאובטח, בלי תקרה. התוכן (תמונות, טקסטים, מחירים) עובר ללוח ניהול פשוט בעברית. אתה עורך שם, והאתר מתעדכן לבד.

מה אפשר לנהל ככה? כמעט הכול:

  • מוצרים ומחירים
  • תמונות וגלריות
  • פוסטים לבלוג
  • המלצות לקוחות
  • מבצעים ובאנרים
  • שעות פתיחה ופרטי קשר
  • שאלות נפוצות
  • תיק עבודות / קטלוג

כל מה שמשתנה באתר — נהיה שדה שאתה עורך לבד.

FIG.02 — THE STACK1:1
האתרrecstudio.dev
הקודNext.js
התוכןSanity
התוכן הוא שכבה נפרדת — נערך לבד, ומתחבר אל מסך האתר.
FIG.03 — CONTENT FLOW1:1
התוכןSanity
הקודNext.js
האתרrecstudio.dev
אתה עורך בתוכן — הקוד מושך את השינוי ומציג אותו באתר. בלי לגעת בקוד.

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

FIG.04 — TWO WORLDS1:1
הבחירה הישנהWix / WordPress
  • עורך לבד — אבל מוגבל ואיטי
  • או: קוד חופשי — אבל רק דרך מתכנת
  • נראה כמו כל אתר אחר
  • נעול בפלטפורמה
הדרך הזוSanity + Next.js
  • עורך לבד, בלי מתכנת
  • מהיר ומדורג גבוה בגוגל
  • עיצוב בלי תקרה
  • הקוד שלך — אתה הבעלים
Sanity

ללוח הניהול במדריך הזה קוראים Sanity — מערכת ניהול תוכן שמשמשת גם חברות כמו Puma ו-Sonos. התוכנית החינמית מספיקה בשפע לאתר של עסק קטן, ולוח הניהול עצמו יושב אצלך בפרויקט — לא אצלם.

לתיעוד הרשמי של Sanity (באנגלית)
FIG.05 — RECAP1:1

מה לזכור

  • התוכן נפרד מהקוד
  • אתה עורך לבד — בלי מתכנת
  • האתר מתעדכן לבד

רואים את זה בפעולה

ככה זה נראה מהכיסא של בעל העסק. נכנסים לכתובת your-site.com/studio, ומקבלים לוח ניהול בעברית. אין צורך בידע טכני.

הדוגמה כאן היא מאתר אמיתי שבניתי — גלריה שמוכרת יצירות. אצלך זה יכול להיות תפריט, קטלוג או בלוג — אותו עיקרון בדיוק.

לוח הניהול בעברית פתוח על מסך לפטופ, על שולחן עבודה
לוח הניהול שלך — נפתח בדפדפן, כמו כל אתר.
  1. 1נכנסים ל-/studio
  2. 2עורכים שדה (תמונה, מחיר, טקסט)
  3. 3לוחצים Publish
  4. 4תוך דקה — באתר
your-site.com/studio

עריכת מוצר

שם המוצר
אגרטל זכוכית
מחיר (בשקלים)
1,200
סטטוס
זמיןנמכרבארכיון
נשמר כטיוטהPublish
your-site.com/studio

כפתור בלחיצה אחת

סמן כנמכר
העבר לארכיון
החזר לאתר (זמין)
your-site.com/studio
זמיניםנמכרובארכיון
  • אגרטל זכוכית1,200
  • כורסת עורנמכר
  • מנורת פליז850

דברים שקורים בלחיצה אחת:

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

בונים את זה — כל הקוד

זה החלק למי שבונה בעצמו (בעלי עסקים — אפשר לדלג ישר לבקשת אתר). לכל שלב יש שני טאבים: פרומפט מוכן להדבקה ב-Claude Code או ב-Codex — שבונה את השלב בשבילך, וטאב קוד אמיתי מתוך אתר שבניתי, למי שרוצה לראות בדיוק מה נבנה. הפרומפטים באנגלית — ככה התוצאה הכי מדויקת. כפתור ההעתקה מעתיק את הטאב הפתוח.

פתח את 7 השלבים — פרומפט + קוד

1התקנה

מתקינים את החבילות, ומאתחלים פרויקט Sanity פעם אחת.

In my existing Next.js project, set up Sanity:
1. Install next-sanity, @sanity/vision and sanity.
2. Run: npx sanity@latest init --env — create a new Sanity project,
   and save the resulting projectId and dataset in .env.local as
   NEXT_PUBLIC_SANITY_PROJECT_ID and NEXT_PUBLIC_SANITY_DATASET.
Do not create any schema yet — that is the next step.

2משתני סביבה (env)

ה-projectId וה-dataset נשמרים כמשתני סביבה — לא בתוך הקוד.

Create sanity/env.ts that centralizes the Sanity env vars:
- Export apiVersion (default "2024-10-01"), dataset and projectId
  from NEXT_PUBLIC_SANITY_API_VERSION / _DATASET / _PROJECT_ID.
- dataset and projectId are required: write an assertValue helper
  that throws a clear "Missing env: ..." error when one is missing.

3הסכמה (Schema)

הסכמה מגדירה אילו שדות יש לכל מוצר — וזה מה שהופך אחר כך לטופס בעברית בלוח הניהול. שים לב ל-slug: שם בעברית מחייב יצירת כתובת לטינית ידנית.

Create a Sanity schema for a product in sanity/schemaTypes/product.ts
(defineType, name "product", Hebrew title "מוצר") with these fields:
1. title — string, title "שם המוצר", required with a Hebrew error.
2. description — text, title "תיאור", 4 rows.
3. price — number, title "מחיר (בשקלים)", minimum 0.
4. status — string radio: available ("זמין") / sold ("נמכר") /
   archived ("בארכיון"). Default available, required.
5. img — image with hotspot, title "תמונה ראשית", required.
6. slug — required, sourced from title. Important: titles are in
   Hebrew, so write a slugify that outputs lowercase Latin letters,
   digits and hyphens only, with a "product-" + timestamp fallback
   when nothing remains.
All field titles must be in Hebrew — they become the editing form
in the Studio.

4ה-Studio: הגדרות, מבנה, וכפתורים

ה-config מרכיב את ה-Studio ב-/studio, ה-structure בונה את הרשימות (זמינים / נמכרו / בארכיון), וה-action מוסיף את כפתור סמן כנמכר בלחיצה אחת.

Wire Sanity Studio into the site, three files:
1. sanity.config.ts — defineConfig with basePath "/studio",
   structureTool (using the structure below), visionTool, and the
   product schema.
2. sanity/structure.ts — a content list with three folders filtered
   by status: "זמינים" (available) / "נמכרו" (sold) /
   "בארכיון" (archived).
3. sanity/actions/productActions.ts — a document action labeled
   "סמן כנמכר" (tone: caution) that only appears on products not yet
   sold: on click it sets status to "sold", publishes, and completes.
   Register it in the config for product documents only.

5שליפת התוכן לאתר

ה-client מוגדר עם perspective: published — רק תוכן שפורסם מגיע לאתר. ה-fetch משתמש ב-revalidate: 60 כך שכל פרסום מופיע תוך כדקה (ISR).

Build the content-fetching layer from Sanity:
1. sanity/lib/client.ts — createClient with useCdn: true and
   perspective: "published", so only published content reaches
   the site.
2. sanity/lib/queries.ts — two GROQ queries with defineQuery:
   all products that are not archived (newest first), and a single
   product by slug. Also project "imageUrl": img.asset->url.
3. sanity/lib/fetch.ts — getAllProducts() and getProductBySlug(slug)
   using next: { revalidate: 60, tags: ["product"] } so every publish
   reaches the site within a minute (ISR).

6שימוש בעמוד + הרכבת ה-Studio

ב-Server Component פשוט קוראים ל-getAllProducts(). את ה-Studio מרכיבים בנתיב ייעודי.

Connect the content to the pages:
1. app/products/page.tsx — a Server Component with revalidate = 60
   that calls getAllProducts() and renders the products; a sold
   product shows a "נמכר" label instead of its price.
2. app/studio/[[...tool]]/page.tsx — mount the Studio with NextStudio
   from next-sanity/studio, with dynamic = "force-static".

7פרסום (Deploy)

מגדירים את משתני הסביבה ב-Vercel, דוחפים ל-git, וזהו.

Prepare the project for production on Vercel:
1. Make sure NEXT_PUBLIC_SANITY_PROJECT_ID and
   NEXT_PUBLIC_SANITY_DATASET are set in Vercel (Production +
   Preview).
2. Push to git and let Vercel build.
3. Add the site domain to the CORS origins in the Sanity project
   settings (otherwise the Studio will not load in production).
4. Verify that /studio loads and that publishing a product shows up
   on the site within a minute.

מה שלמדתי: עברית ו-RTL

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

הטופס בעברית מגיע מהסכמה

כל כותרת שדה שכותבים בעברית בסכמה (שלב 3) הופכת לשדה בעברית בלוח הניהול. זה כל הסוד מאחורי לוח ניהול בעברית — אין הגדרה מיוחדת מעבר לזה.

שם בעברית לא יוצר כתובת

כתובת של דף באינטרנט חייבת אותיות לטיניות. שם מוצר בעברית לא מייצר אותה לבד — בלי המרה אוטומטית, דף המוצר פשוט לא ייפתח. בגלל זה הסכמה שלנו ממירה את השם לכתובת לטינית אוטומטית.

המרכאות העבריות שוברות את הקוד

המקלדת העברית מכניסה לפעמים גרשיים עבריים — תו שנראה בדיוק כמו מרכאות רגילות, אבל מפיל את האתר. בקוד משתמשים תמיד במרכאות רגילות, ושווה לבקש מה-AI לחסום את התו הזה אוטומטית.

עברית צריכה כיוון — ואוויר

את כיוון הקריאה (RTL) קובעים פעם אחת, ברמת האתר — לא מתקנים נקודתית בכל רכיב. ועברית צריכה ריווח שורות גבוה יותר מאנגלית, אחרת הטקסט נחנק.

מספרים נקראים הפוך

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

אופציונלי: עובדים עם Claude Code או Codex? הדביקו את זה פעם אחת — והכללים האלה ייכנסו לזיכרון הקבוע של הפרויקט. מעכשיו ה-AI יישם אותם לבד, בכל מה שהוא בונה.

prompt
text
Add a "Hebrew / RTL rules" section to my project memory file
(CLAUDE.md — or AGENTS.md if this project uses Codex). Create the
file if it does not exist. The rules:

1. Never use the Hebrew gershayim/geresh characters (U+05F4, U+05F3)
   in code files — they break the parser. Always use ASCII quotes.
2. Page direction is set once: <html lang="he" dir="rtl"> in the
   root layout. Never patch direction per component.
3. Hebrew body text needs line-height of at least 1.7.
4. Always use CSS logical properties (margin-inline-start,
   padding-inline-end, start/end) — never left/right.
5. Wrap phone numbers and other LTR runs inside Hebrew text with
   <span dir="ltr">. Prices use the ₪ symbol.
6. Sanity: all schema field titles in Hebrew (they become the
   editing form); slugs must be generated in Latin characters only.

כל המדריך, בתמונה אחת

FIG.06 — THE WHOLE STORY3:4
אינפוגרפיקה מצוירת ביד של כל המדריך בחמישה פאנלים: הבעיה, מפרידים תוכן מקוד, רואים בפעולה, בונים את זה, ומה שלמדתי
לחיצה פותחת בגודל מלא

בניתי בדיוק את זה לגלריה אמיתית.

רוצה אתר שאתה באמת הבעלים שלו — מהיר, יפה, ושאתה עורך לבד? שלח לי "אתר" בוואטסאפ, ונדבר.

המדריך חינמי וכל הקוד פתוח. רוצה שאני אבנה לך את זה — זה מה שאני עושה.