גל חדד MSc במערכות מידע

וורדפרס

וורדפרס

Bedrock: וורדפרס עם Composer ו-Git, ולמה זה משנה

אם אתם בונים אתרי וורדפרס באופן מקצועי, סביר שכבר נתקלתם ברגע הזה: רוצים לשים את הפרויקט תחת Git, מריצים git status, ומקבלים רשימה של אלפי קבצים. ליבת וורדפרס, כל התוספים, כל התבניות, תיקיית ההעלאות, הכל ערבוב אחד גדול. אתם מחפשים את שלוש השורות שבאמת כתבתם, והן טבועות בתוך עשרת אלפים קבצים שהורדתם.

זה לא באג של Git, זה פשוט מבנה הפרויקט של וורדפרס “רגיל”, שלא תוכנן לעבודה מודרנית. המדריך הזה הוא על Bedrock, הדרך של Roots לנהל אתר וורדפרס עם Composer ו-Git, כמו שמנהלים כל פרויקט תוכנה רציני אחר.

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

הכאב של וורדפרס “רגיל”

הדרך הקלאסית, להוריד zip, להעתיק wp-content, להעלות עם Duplicator, עובדת מצוין כל עוד אתם לבד ובלי דפלוי מסודר. ברגע שעוברים לעבודה מקצועית, היא מתחילה לכאוב בארבעה מקומות:

  • הכל מעורבב. ליבה, תוספים, תבניות, העלאות והקוד שלכם יושבים באותה תיקייה. אין קו ברור בין מה שכתבתם לבין מה שהורדתם.
  • Git מאבד משמעות. commit של אתר שלם = אלפי קבצי ליבה ועוד כל התוספים. עדכון תוסף אחד מייצר diff ענק של קוד שלא כתבתם ולא תקראו לעולם.
  • אין תיעוד של מה מותקן. איזו גרסת WooCommerce רצה? התשובה היחידה היא “תיכנס לתיקייה ותסתכל”. שחזור מדויק של אותו אתר במקום אחר הוא עבודת יד שבירה.
  • סודות חשופים. סיסמת מסד הנתונים יושבת ב-wp-config.php. או שהיא נכנסת ל-commit (גרוע), או שעורכים אותה ידנית בכל שרת (שביר). וה-wp-config.php הזה, על הסיסמה שבתוכו, יושב בתוך התיקייה הציבורית שכל הדפדפנים מגיעים אליה.

ועוד נקודה שמכאיבה בדפלוי: אותו wp-config.php הוא זהה בכל מקום. הוא לא יודע להבדיל בין המחשב המקומי שלכם, שרת ה-staging והייצור, אלא אם תזריקו לו פריצות מסוג if (localhost). זה עובד, אבל זה מלוכלך.

הרעיון המרכזי: וורדפרס כ-dependency

ההיגיון שמאחורי Bedrock הוא אחד, וזה העיקר:

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

במקום לשמור ב-repo אלפי קבצי ליבה, שומרים קובץ טקסט קטן שאומר “האתר הזה משתמש בוורדפרס בגרסה X, ב-WooCommerce בגרסה Y, ובתבניות האלה”. כלי בשם Composer קורא את הרשימה ומוריד את הקבצים בפועל, לפי דרישה.

מי שעבד עם Docker יזהה כאן את אותו רעיון: הרשימה ה-declarative היא מקור האמת, ואת הקבצים הכבדים אפשר לשחזר ממנה בכל רגע. ה-repo מכיל רק שלושה דברים: הקוד שלכם, רשימת ה-dependencies, וה-config. נקי, קטן, ומתעד בדיוק ממה האתר עשוי.

Composer הוא מנהל החבילות של PHP, בדיוק כמו ש-npm הוא מנהל החבילות של Node. אם עבדתם עם npm, התחושה תהיה מוכרת מאוד.

מבנה התיקיות, ולמה כל דבר זז

המבנה של Bedrock נראה מוזר במבט ראשון, אבל הוא הגיוני לגמרי. נשווה אותו לקלאסי:

וורדפרס קלאסי, מה שכולנו מכירים:

public_html/ ← כל זה הוא ה-web root הציבורי
├── wp-admin/ wp-includes/ ← הליבה
├── wp-content/{themes,plugins,uploads}
├── wp-config.php ← config + סיסמת DB, הכל כאן
└── index.php

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

ועכשיו Bedrock:

bedrock-lab/ ← שורש הפרויקט (לא נגיש מהדפדפן)
├── composer.json / composer.lock ← רשימת dependencies + נעילת גרסאות
├── vendor/ ← ספריות PHP של Composer
├── config/
│ ├── application.php ← מחליף את רוב wp-config.php
│ └── environments/ ← development.php, staging.php, production.php
├── .env ← סודות + DB, מחוץ ל-web root
└── web/ ← ה-WEB ROOT (רק זה ציבורי)
├── wp/ ← ליבת וורדפרס כאן
├── app/ ← זה wp-content, בשם אחר
│ └── {themes,plugins,mu-plugins,uploads}
└── index.php wp-config.php ← bootstrap זעיר

שלוש הזזות, וכל אחת פותרת אחת מהבעיות שלמעלה.

web root נפרד, שדרוג אבטחה אמיתי. בקלאסי, ה-wp-config.php עם סיסמת מסד הנתונים יושב בתוך התיקייה הציבורית. ב-Bedrock רק תיקיית web/ מוגשת על ידי השרת. ה-composer.json, תיקיית vendor/, תיקיית config/, ובמיוחד קובץ ה-.env עם כל הסודות, כולם יושבים מעל ה-web root, מחוץ להישג ידו של כל דפדפן. זה לדעתי השדרוג האבטחתי הגדול ביותר של Bedrock, וקשה לחזור אחורה אחרי שמתרגלים אליו.

הליבה עוברת ל-web/wp/, ליבה כ-dependency מתחלף. הליבה מבודדת בתת-תיקייה משלה, מותקנת ומעודכנת רק על ידי Composer. אתם לא נוגעים בה, לא עושים לה commit, ועדכון וורדפרס הוא פשוט שינוי מספר גרסה בקובץ אחד. בגלל ההזזה הזו, ה-front-end נמצא ב-/ אבל לוח הבקרה יושב ב-/wp/wp-admin.

wp-content הופך ל-web/app/, הקוד שלכם, מופרד בבירור. מבחינה פונקציונלית זו אותה תיקייה בדיוק: אותם themes/, plugins/, mu-plugins/, uploads/. השם שונה ל-app כדי לסמן “האפליקציה שלכם” מול מנוע הליבה ב-wp/. ערכת בלוקים FSE נכנסת ל-web/app/themes/ ועובדת רגיל לחלוטין.

composer.json מול composer.lock, כוונה מול מצב בפועל

זה החלק השימושי ביותר בפועל. אחרי הקמת פרויקט Bedrock, הוספת תוסף נראית כך:

Terminal window
ddev composer require wpackagist-plugin/classic-editor

רק רגע לפני שממשיכים, מאיפה מגיע ה-wpackagist-plugin/ הזה? Composer מושך חבילות מ-Packagist, המאגר המרכזי של PHP, ותוספי וורדפרס פשוט לא יושבים שם. הם מגיעים מ-WPackagist, מאגר שעוטף את ספריית התוספים והתבניות הרשמית של WordPress.org ומגיש אותה כחבילות Composer. את המאגר רושמים פעם אחת לכל פרויקט, אחרת Composer יחזיר Could not find package:

Terminal window
composer config repositories.wpackagist composer https://wpackagist.org

זו ברירת המחדל הסטנדרטית, וגם זו שאני ממליץ עליה למתחילים. אני עצמי משתמש ב-WP Packages, מראה (mirror) פתוח-קוד שמתעדכן כל חמש דקות ומהיר בערך פי 17 מ-WPackagist. רק שימו לב: הוא משתמש ב-namespace משלו, wp-plugin/ במקום wpackagist-plugin/ (למשל composer require wp-plugin/woocommerce), כך שזו לא רק החלפת כתובת, גם שורות ה-require משתנות. למתחילים WPackagist הוא הבחירה הנכונה; את ההחלפה תמיד אפשר לעשות בהמשך.

זה המחליף של “Add New → Upload Plugin”. שלושה דברים קורים אוטומטית: השורה נוספת ל-composer.json, Composer מוריד את התוסף ושם אותו ב-web/app/plugins/classic-editor/, והגרסה המדויקת נכתבת ל-composer.lock. שני הקבצים האלה הם מערכת אחת, ושניהם נכנסים ל-Git:

  • composer.json מחזיק את הכוונות שלכם, כטווחי גרסאות. "^1.6" אומר “גרסה 1.6 או כל 1.x מאוחרת יותר”, כלומר עדכונים תואמים, בלי קפיצת major ששוברת. אתם עורכים אותו ביד.
  • composer.lock מחזיק את הגרסאות המדויקות שהותקנו בפועל, למשל 1.6.7. הוא נוצר על ידי המכונה, והוא snapshot מדויק של מצב האתר.

ההפרדה הזו פותרת בדיוק את הדאגה מ”עדכונים מסובכים”. יש שתי פקודות:

Terminal window
composer install # מתקין בדיוק מה שכתוב ב-lock, שחזורי, בלי הפתעות
composer update # מושך גרסאות חדשות לפי הטווחים, וכותב מחדש את ה-lock

install רץ על השרת בזמן דפלוי, ומבטיח שתקבלו בייצור את אותן גרסאות מדויקות שבדקתם. update רץ אצלכם בזמן פיתוח. עדכון תוסף הוא תהליך מבוקר: composer update במחשב המקומי, בדיקה, commit של ה-composer.lock, ואז דפלוי. מתועד והפיך.

פלט הטרמינל של composer require, השורה שנוספת ל-composer.json והגרסה שננעלת ב-composer.lock.

נקודה אחת שמבלבלת בהתחלה: Composer מתקין קבצים, אבל לא מפעיל תוספים. Composer מנהל את הקבצים, מוריד, מעדכן, מסיר. וורדפרס ממשיך לנהל את המצב, פעיל או לא פעיל, הגדרות. אחרי composer require, אתם מפעילים את התוסף כרגיל, או מ-WP-CLI או מלוח הבקרה:

Terminal window
ddev wp plugin activate classic-editor

DISALLOW_FILE_MODS: למה כדאי לכבות התקנות מלוח הבקרה

בתוך config/application.php יושבות שתי שורות שמשנות את ההתנהגות באופן המורגש ביותר:

Config::define('DISALLOW_FILE_EDIT', true); // אין עורך קוד בלוח הבקרה
Config::define('DISALLOW_FILE_MODS', true); // אין התקנה/עדכון מלוח הבקרה

בייצור, אי אפשר להתקין או לעדכן תוספים ותבניות מתוך לוח הבקרה של וורדפרס. כפתורי “Add New → Upload” פשוט כבויים, בכוונה. בהתחלה זה מרגיש כמו אובדן שליטה. בפועל זו ההחלטה שמחזיקה את כל השיטה: היא מבטיחה שה-composer.json תמיד משקף את המציאות, כי אין דרך אחרת להכניס קבצים. ובנוסף, זו הקשחת אבטחה אמיתית, לוח בקרה פרוץ לא יכול להתקין תוסף זדוני, כי המנגנון להתקנה פשוט לא קיים.

במחשב המקומי, אגב, Bedrock מדליק את ההגדרה הזו מחדש, כדי שתוכלו להתנסות בחופשיות. רק שזכרו: כל מה שתתקינו ככה מקומית לא נכנס ל-composer.json, לא יעבור דפלוי, ולא יתועד. אז גם מקומית, כל מה שאמור להישאר עובר ב-composer require.

שלושת קבצי ה-config

בוורדפרס רגיל, ה-wp-config.php עושה שלוש עבודות בו-זמנית: מחזיק סודות, מחזיק הגדרות, ומנסה להתנהג שונה לפי סביבה. Bedrock מפצל את שלוש העבודות לשלושה מקומות, וזה מה שהופך את הדפלוי לבטוח.

  • .env, סודות וערכים פר-מכונה. כאן יושב כל מה ששונה בין סביבות או סודי: פרטי מסד הנתונים, כתובת האתר, ערך WP_ENV, ה-salts, מפתחות API. הקובץ יושב מעל ה-web root, והוא נמצא ב-.gitignore. לכל סביבה, המחשב שלכם, staging, production, יש .env משלה עם הערכים שלה. הקובץ הזה לעולם לא נכנס ל-Git.
  • config/application.php, הגדרות משותפות. מה שזהה בכל מקום: התיקייה app, הליבה ב-wp, ה-DISALLOW_FILE_MODS, מגבלות revisions. הוא קורא את הסודות דרך helper בשם env(), כך שהקוד נשאר גנרי והסוד נשאר ב-.env. הקובץ הזה כן נכנס ל-Git.
  • config/environments/development.php (ו-staging, ו-production), דריסות פר-סביבה. המחליף הנקי לפריצות if (localhost). לפי הערך של WP_ENV, Bedrock טוען בדיוק אחד מהקבצים האלה. development מדליק שגיאות גלויות ולוג של queries, production מכבה הכל. גם הם נכנסים ל-Git.

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

על ה-salts, ברצינות

ב-.env.example יש שמונה שורות salts עם הערך generateme. אלה מפתחות ההצפנה של עוגיות ההתחברות בוורדפרס. במחשב המקומי, אתר יעלה גם עם הערכים הדמה האלה, אבל לפרויקט אמיתי חובה לייצר salts אמיתיים. השארת generateme בייצור היא חור אבטחה ממשי. מייצרים אותם מ-roots.io/salts.html, שמחזיר פלט מוכן ישר בפורמט .env, ומדביקים ל-.env של הייצור.

הדף roots.io/salts.html עם שמונה שורות ה-salts המוכנות להעתקה ל-.env.

Bedrock זה לא Sage (וזה לא Trellis)

הרבה אנשים מתבלבלים בין שלושת הכלים של Roots, אז נסדר את זה. Bedrock, Sage ו-Trellis הם שלושה כלים נפרדים של אותה קבוצה, ואנשים נוטים לערבב ביניהם.

Bedrock נוגע אך ורק לתשתית: מבנה התיקיות, ה-config, ניהול ה-dependencies. הוא לא נוגע, ולו במעט, לאופן שבו אתם בונים את התבנית עצמה. Sage, לעומתו, הוא starter theme שכן משנה את אופן בניית התבנית, לכיוון מנוע תבניות בשם Blade ובניית theme קלאסית, לא-FSE.

לכן המשפט החשוב: אפשר להשתמש ב-Bedrock עם ערכת בלוקים FSE לגמרי בלי Sage. Bedrock ו-FSE פועלים בצירים שונים. Bedrock מטפל ב”איפה הקבצים יושבים ואיך מתקינים אותם”; FSE מטפל ב”איך בונים את העיצוב”. אתם מכניסים ערכת בלוקים FSE לתיקיית web/app/themes/ של פרויקט Bedrock, והיא עובדת בדיוק כמו בכל וורדפרס אחר. ככה אני עובד יום-יום: Bedrock כתשתית, FSE כשכבת העיצוב, בלי Sage באמצע.

מה צריך כדי לנסות את זה

ההקמה עצמה היא מדריך נפרד, אבל הנה התמונה העקרונית של מה שמעורב, וזה זהה ב-macOS וב-Windows.

הבסיס הוא DDEV, סביבת פיתוח מקומית מבוססת-Docker. את מנוע ה-Docker מספק Docker Desktop, שעובד גם ב-macOS וגם ב-Windows. הוא חייב לרוץ ברקע גם כשכל העבודה שלכם היא בשורת הפקודה, שורת הפקודה רק מדברת עם המנוע, היא לא המנוע עצמו.

ב-macOS: מתקינים את Docker Desktop ואת DDEV (הדרך הנקייה היא דרך Homebrew), והעבודה כולה בטרמינל הרגיל.

ב-Windows: עובדים בתוך WSL2, סביבת לינוקס בתוך Windows. גם Docker Desktop משתמש ב-WSL2 כמנוע. מתקינים את WSL2, ובתוכו את DDEV, וכל הפקודות רצות מתוך טרמינל ה-WSL2, לא מתוך PowerShell. שימו לב לנקודה הזו, היא מקור לבלבול אצל מי שמגיע מ-Windows.

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

Terminal window
ddev config --project-type=wordpress --docroot=web --create-docroot
ddev start
ddev composer create-project roots/bedrock

(ואז הגדרת ה-.env.) הפקודה השלישית מורידה את שלד Bedrock, מייצרת את ה-composer.json, ומושכת את ליבת וורדפרס ואת חבילות הבסיס. אתם מקבלים אתר מנוהל-Composer, מוכן-FSE, עם HTTPS, וליבה ב-web/wp, מבלי שאף קובץ ליבה אחד יושב ב-repo שלכם. את ההקמה המלאה, צעד אחר צעד, אכסה במדריך נפרד.

אז למה זה משנה

קחו צעד אחורה ותראו מה השתנה. ה-repo שלכם מכיל עכשיו רק קוד שכתבתם, רשימת dependencies, וקבצי config. git status מראה לכם בדיוק את העבודה שלכם, נקייה. גרסת כל תוסף מתועדת ונעולה. הסודות יושבים מחוץ ל-Git ומחוץ לתיקייה הציבורית. ואותו קוד בדיוק רץ במחשב שלכם, ב-staging ובייצור, כשרק קובץ סודות אחד משתנה ביניהם.

מעבר למבנה התיקיות, Bedrock משנה את הדרך שבה חושבים על אתר וורדפרס. אחרי שעובדים ככה תקופה, חזרה ל-wp-content שמעתיקים ב-FTP מרגישה כמו לעבוד בלי רשת ביטחון. השקעה קטנה בהבנת המבנה, ותשלום שמחזיר את עצמו בכל דפלוי ובכל עדכון.


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

תגובות

טוען תגובות…

השארת תגובה

התגובות עוברות אישור לפני הפרסום.

להישאר בקשר

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

אפשר לבטל בכל רגע, בקליק אחד.