מה זה ACF Repeater Field ולמה הוא קיים
וורדפרס לא נבנה מלכתחילה לניהול תוכן מובנה וחוזר. שדה טקסט אחד, עורך ויזואלי אחד, ותו לא. כשמפתח צריך לאפשר למנהל אתר להוסיף רשימה של עובדים, גלריית פרויקטים, או טבלת מחירים עם מספר שורות משתנה, הפתרון הרגיל של וורדפרס פשוט לא מספיק.
ACF Repeater Field, חלק מהתוסף Advanced Custom Fields Pro, פותר בדיוק את הבעיה הזו. הוא מאפשר להגדיר קבוצת שדות שחוזרת על עצמה מספר פעמים בלתי מוגבל. מנהל האתר מוסיף שורות דרך ממשק ידידותי, והמפתח מציג אותן בתבנית PHP עם לולאה פשוטה. התוצאה: תוכן דינמי ומובנה שניתן לנהל בלי לגעת בקוד.
הפופולריות של ACF Pro נובעת מכך שהוא מגשר על הפער בין מה שוורדפרס מציע כברירת מחדל לבין מה שפרויקטים אמיתיים דורשים. לפי נתוני WordPress.org, ACF מותקן על יותר מ-6 מיליון אתרים פעילים, מה שהופך אותו לאחד התוספים הנפוצים ביותר בפלטפורמה.
הגדרת Repeater Field בממשק ACF
לפני שכותבים שורת PHP אחת, צריך להגדיר את השדה נכון בממשק. ב-ACF Pro, יוצרים קבוצת שדות חדשה, מוסיפים שדה מסוג "Repeater", ובתוכו מגדירים את תת-השדות שיחזרו בכל שורה.
לדוגמה, עבור רשימת חברי צוות, תת-השדות יכולים להיות:
- שם (Text)
- תפקיד (Text)
- תמונה (Image)
- קישור לפרופיל (URL)
- ביוגרפיה קצרה (Textarea)
שם השדה שמגדירים ב-ACF הוא המפתח שישמש בקוד PHP. אם קוראים לשדה team_members, זה בדיוק המחרוזת שתעבירו ל-have_rows(). שגיאת כתיב קטנה כאן גורמת ל-have_rows() להחזיר false, ומפתחים מתחילים מבלים שעות בחיפוש אחרי הבאג.
חשוב גם להגדיר את ה-Location Rules נכון, כלומר באיזה סוג פוסט, עמוד, או הקשר יופיע השדה. שדה שמוגדר רק לפוסטים מסוג "post" לא יופיע בעמודים רגילים, גם אם הקוד נכון לחלוטין.

כיצד כותבים לולאת PHP בסיסית עם have_rows
הלולאה הבסיסית של ACF Repeater Field ב-PHP בנויה על שלוש פונקציות: have_rows() בודקת אם יש שורות, the_row() מתקדמת לשורה הבאה, ו-the_sub_field() מציגה את ערך תת-השדה.
קוד בסיסי נראה כך:
if( have_rows('team_members') ):
while( have_rows('team_members') ): the_row();
echo '';
echo '' . get_sub_field('name') . '
';
echo '' . get_sub_field('role') . '
';
echo '';
endwhile;
endif;
כמה נקודות שחשוב להבין: the_sub_field() מדפיסה ישירות, ואילו get_sub_field() מחזירה את הערך כמשתנה. כשצריך לבדוק ערך לפני הצגתו, לעבד אותו, או להעביר אותו לפונקציה אחרת, תמיד משתמשים ב-get_sub_field(). שימוש ב-the_sub_field() בתוך תנאי if יגרום לשגיאה כי הפונקציה לא מחזירה ערך שניתן להשוות.
אם הלולאה רצה מחוץ ל-Loop הרגיל של וורדפרס, צריך להעביר את ה-Post ID כפרמטר שני: have_rows('team_members', get_the_ID()). בתבניות כמו single.php זה בדרך כלל לא נדרש, אך ב-WP_Query מותאמת זה הכרחי.
קבלת נתוני Repeater כמערך PHP
לולאת have_rows() מתאימה להצגה ישירה ב-HTML, אך לא תמיד זה מה שצריך. כשרוצים לעבד את הנתונים, למיין אותם, לסנן לפי תנאי, או להעביר אותם ל-JavaScript, עדיף לקבל את כל הנתונים כמערך אחד.
הפונקציה get_field() על שדה Repeater מחזירה מערך דו-ממדי. כל אלמנט במערך הוא שורה, וכל שורה היא מערך אסוציאטיבי עם מפתחות לפי שמות תת-השדות:
$team = get_field('team_members');
if( $team ) {
usort($team, function($a, $b) {
return strcmp($a['name'], $b['name']);
});
foreach( $team as $member ) {
echo $member['name'] . ' - ' . $member['role'];
}
}
שיטה זו שימושית במיוחד כשמייבאים נתונים ממקור חיצוני, כמו API או קובץ CSV, ורוצים לשמור אותם ישירות לשדה Repeater. הפונקציה update_field() מקבלת מערך בפורמט זהה ושומרת את כל השורות בבת אחת.
אחת הטעויות שאנחנו רואים לעתים קרובות: מפתחים מנסים לשמור נתונים עם update_field() כשהמערך לא בנוי בפורמט הנכון. ACF מצפה למערך שטוח של שורות, לא למערך מקונן עם מפתח נוסף. כדאי תמיד לבדוק עם var_dump() לפני שמנסים לשמור.

לולאות מקוננות: Repeater בתוך Repeater
ACF Pro תומך בקינון של שדות Repeater עד 3 רמות עומק. תרחיש נפוץ: רשימת קטגוריות, שבכל אחת יש רשימת פריטים, ובכל פריט יש רשימת תכונות. בפועל, קינון מעבר לשתי רמות הופך את הקוד לקשה לתחזוקה ואת הביצועים לבעייתיים.
קוד לשתי רמות קינון:
if( have_rows('categories') ):
while( have_rows('categories') ): the_row();
echo '' . get_sub_field('category_name') . '
';
if( have_rows('items') ):
while( have_rows('items') ): the_row();
echo '' . get_sub_field('item_title') . '
';
endwhile;
endif;
endwhile;
endif;
מניסיון שלנו, כשפרויקט דורש יותר משתי רמות קינון, כדאי לשקול ארכיטקטורה אחרת לגמרי. לעתים עדיף ליצור Custom Post Type נפרד עם קשרים בין פוסטים, במקום לקנן Repeaters עמוק. זה גם יותר ניתן לתחזוקה וגם מהיר יותר מבחינת שאילתות מסד הנתונים.
נקודה טכנית חשובה: בתוך לולאה מקוננת, have_rows() ו-the_sub_field() פועלות על הרמה הנוכחית אוטומטית. אין צורך להעביר פרמטרים נוספים, ACF עוקב אחרי ה"מיקום" הנוכחי בלולאה.
שימוש ב-Repeater Field בעמוד אפשרויות
ACF Options Page מאפשר להגדיר שדות גלובליים שאינם שייכים לפוסט ספציפי, כמו פרטי יצירת קשר, שעות פעילות, או רשימת סניפים. שדות Repeater על עמוד אפשרויות עובדים בדיוק אותו דבר, עם שינוי אחד: מעבירים 'option' כפרמטר שני.
if( have_rows('branch_list', 'option') ):
while( have_rows('branch_list', 'option') ): the_row();
echo get_sub_field('branch_name');
endwhile;
endif;
שכחה להוסיף את 'option' היא אחת הסיבות הנפוצות ביותר ל-have_rows() שמחזיר false על שדות גלובליים. הקוד נראה נכון לחלוטין, אבל ללא הפרמטר הזה ACF מחפש את השדה על הפוסט הנוכחי ולא מוצא כלום.
אם האתר שלכם משתמש ב-WordPress Multisite, שימו לב שעמוד האפשרויות ברירת המחדל הוא per-site. יש אפשרות להגדיר options page גלובלי לכל הרשת עם הפרמטר 'show_in_menu' ו-capability מתאים, אך זה דורש הגדרה מפורשת.
אופטימיזציית ביצועים בשאילתות Repeater
כל שורה ב-Repeater Field נשמרת כרשומה נפרדת בטבלת wp_postmeta. שדה Repeater עם 50 שורות ו-5 תת-שדות בכל שורה = 251 רשומות במסד הנתונים (1 לספירת השורות + 250 לנתונים). על אתר עם מאות פוסטים, זה מצטבר במהירות.
כמה אסטרטגיות לשיפור ביצועים:
- שימוש ב-Object Cache (Redis או Memcached) כדי לשמור תוצאות get_field() בזיכרון
- הימנעות מ-Repeater Fields בלולאות WP_Query גדולות, במיוחד בארכיב עם עשרות פוסטים
- שקילת שימוש ב-Transients API לשמירת תוצאות מעובדות לזמן קצוב
- שימוש ב-get_field() פעם אחת ושמירה במשתנה, במקום קריאות חוזרות לאותו שדה
ברוב המקרים, אתר עם תנועה בינונית לא יחוש בהבדל. הבעיה מתחילה כשיש עמוד ארכיב שמציג 20 פוסטים, כל אחד עם Repeater של 30 שורות. שם כבר שווה להשקיע בקאשינג.
שגיאות נפוצות ואיך להימנע מהן
ברוב הפרויקטים שאנחנו רואים, הבאגים ב-ACF Repeater מגיעים מאותן 4-5 סיבות חוזרות. הנה הנפוצות ביותר:
שימוש ב-get_field() במקום get_sub_field() בתוך הלולאה. get_field() מחפשת שדה ראשי, לא תת-שדה. בתוך לולאת have_rows() חייבים להשתמש ב-get_sub_field() או the_sub_field().
אי-בדיקה אם have_rows() מחזיר true לפני הלולאה. אם השדה ריק, הלולאה פשוט לא תרוץ, אבל קוד שמניח שיש נתונים עלול לגרום ל-PHP notices מיותרים.
שכחת wp_reset_postdata() אחרי WP_Query. כשמשתמשים ב-Repeater בתוך לולאת WP_Query מותאמת, חייבים לאפס את הלולאה הגלובלית בסיום. אחרת, have_rows() בחלקים אחרים של הדף עלול לפעול על הפוסט הלא נכון.
הצגת תמונות מ-Repeater בפורמט שגוי. שדה תמונה ב-ACF יכול להחזיר ID, URL, או מערך מלא, תלוי בהגדרת "Return Format". אם מצפים למערך ומקבלים ID, הקוד ייכשל בשקט.
לפיתוח אתרים מקצועי שמשלב כלים כמו ACF עם ארכיטקטורה נכונה, כדאי לקרוא על טיפים לפיתוח אתרים אפקטיבי שמסבירים כיצד לבנות בסיס טכני יציב.
Repeater Field עם JavaScript ו-REST API
ACF Pro כולל תמיכה ב-WordPress REST API. שדות Repeater נחשפים אוטומטית ב-endpoint של הפוסט כשמפעילים את האפשרות "Show in REST API" בהגדרות קבוצת השדות. הנתונים מגיעים כמערך JSON מובנה, מה שמאפשר שימוש בהם ב-React, Vue, או כל JavaScript framework.
דוגמה לגישה לנתוני Repeater דרך REST API:
fetch('/wp-json/wp/v2/posts/123')
.then(res => res.json())
.then(post => {
const members = post.acf.team_members;
members.forEach(member => {
console.log(member.name, member.role);
});
});
חשוב לדעת: שדות תמונה ב-Repeater דרך REST API מחזירים את ה-ID של הקובץ, לא את ה-URL. צריך לבצע קריאה נוספת ל-/wp-json/wp/v2/media/{id} כדי לקבל את ה-URL, או לשנות את ה-Return Format ל-"Image Array" בהגדרות ACF.
לאתרים שמשלבים WordPress כ-headless CMS עם פרונטאנד נפרד, Repeater Fields דרך REST API הם כלי עוצמתי. הם מאפשרים לצוות התוכן לנהל מבנה מורכב דרך ממשק מוכר, בעוד הפרונטאנד מקבל JSON נקי ומובנה.
Repeater Field בבלוקים מותאמים של Gutenberg
ACF Blocks מאפשרים לרשום בלוקים מותאמים אישית ב-Gutenberg שמשתמשים בשדות ACF, כולל Repeater. הבלוק מוגדר ב-PHP עם acf_register_block_type(), ותבנית ה-PHP שלו יכולה להשתמש בכל פונקציות ACF הרגילות.
ההבדל המשמעותי: בתוך תבנית בלוק ACF, הקשר השדה הוא הבלוק עצמו, לא הפוסט. לכן have_rows() עובד ישירות ללא צורך ב-Post ID. זה מפשט את הקוד אך גם אומר שנתוני הבלוק נשמרים בתוך תוכן הפוסט כ-JSON, לא ב-postmeta.
לאתרים שמשלבים תוכן דינמי עם אסטרטגיית תוכן ארוכת טווח, כדאי לקרוא על בניית בלוג לקידום אורגני שמסביר כיצד ארכיטקטורת תוכן נכונה משפיעה על הנראות בגוגל.
מגבלה שכדאי להכיר: עריכה ויזואלית של שדות Repeater ישירות בעורך Gutenberg, כלומר הוספה והסרה של שורות בתצוגה חיה, עדיין לא חלקה לחלוטין. ממשק ה-ACF הקלאסי בסרגל הצד של Gutenberg עדיין נוח יותר לעריכת Repeaters מורכבים.
בדיקות ו-Debugging של Repeater Fields
כשלולאת Repeater לא עובדת כצפוי, יש סדר בדיקות שחוסך זמן. קודם כל, מוסיפים var_dump(get_field('field_name')) לפני הלולאה. אם מקבלים null, הבעיה היא בשם השדה או בהקשר. אם מקבלים מערך ריק, השדה קיים אך אין נתונים. אם מקבלים מערך עם נתונים, הבעיה היא בלולאה עצמה.
כלי שימושי: התוסף Query Monitor מציג את כל שאילתות מסד הנתונים שנוצרו על ידי ACF, כולל כמה שאילתות כל Repeater מייצר. זה עוזר לזהות צווארי בקבוק בביצועים.
לסביבת פיתוח, כדאי להפעיל WP_DEBUG ו-WP_DEBUG_LOG ב-wp-config.php. ACF כותב אזהרות ל-debug log כשמשתמשים בפונקציות בצורה שגויה, למשל קריאה ל-the_sub_field() מחוץ ללולאה פעילה. הודעות אלו לא מופיעות בפרונטאנד בסביבת production, מה שהופך אותן לקשות לאיתור ללא debug mode.
לאתרים שמשתמשים ב-ACF בשילוב עם תוספי SEO, כדאי לבדוק את השימוש בתוספי SEO בוורדפרס כדי לוודא שהתוכן הדינמי שנוצר דרך Repeater Fields נסרק ומאונדקס כראוי.



