אב

תתי קטגוריות בתפריט וורדפרס

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

מבחינת הניהול, עורך האתר צריך ליצור/להזיז אותן, ולפעמים לשלוט בסדר ההופעה שלהן (את זאת אנו עושים ע”י התוסף my category order. אמנם קצת ישן, אבל עובד). אבל נראה היה לי מיותר שיצטרך אחרי זה להכנס לתפריט ולהוסיף / להזיז אותן גם שם.

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

שיטוטיי הביאו אותי למאמר הוספה דינמית של תתי פריטים לתפריט. היה שם יופי של קוד עם הסברים איך להוסיף תתי פריטים. אמנם היה מדובר שם על הוספה של פריטים מסוג התאמה אישית, דהיינו קישורים ולא תתי קטגוריות, אבל לא קשה היה לעשות את ההמרה: בכל איטרציה של הלולאה על הפריטים בתפריט, בדקתי אם הפריט הנוכחי הוא קטגוריה. אם כן, קראתי ל-get_categories(), עם ה-id שלו (נמצא ב- $item->object_id  – לא להתבלבל עם $item->ID, שהוא ה-id של הפריט בתפריט! ). גם חשוב לי להעביר את הפרמטר hierarchical כדי שתתי הקטגוריות של תתי הקטגוריות תגענה כראוי. וכך קיבלתי לי יופי של תפריט עם קטגוריות, תתי קטגוריות, ותתי קטגוריותיהן.אך האם תמו כל תלאותיי?

אמנם קיבלתי כעת את כל תתי הקטגוריות, ותתי תתיהן, אבל לא קיבלתי שום אינדיקציה מי הפריטים של ילדים, ומי הם נכדים – קיבלתי רשימת li-ים שטוחה. בד”כ כשיש בתפריט כמה רמות, כל רמה שיש לה תת רמה, מקבלת class בשם menu-item-has-children. אבל מאחר שפה הפריטים אינם נמצאים בתפריט אלא מתווספים אליו דרך הקוד – הם לא קיבלו class כזה.

לא נותרה לי ברירה אלא לתת להם את ה-class הזה בעצמי: עבור כל פריט, בדקתי אם במערך הקטגוריות, יש קטגוריה שה-ID שלה הוא ID של parent של אחד האיברים במערך (כלומר, האם יש לקטגוריה זאת ילדים). לשם כך השתמשתי בפונקציה array_filter() שמפלטרת איברים במערך לפי תנאי שנותנים לה. פונקציה מהממת, שממש חוסכת שורות קוד ארוכות. אמנם היה לי אתגר קטן מאחר שרציתי להשתמש באיבר הנוכחי, והפונקציה עומדת בפני עצמה ולא מכירה אותו, הייתי מוכרחה למצוא דרך לגרום לה שתכיר אותו. אך לאחר חיפושים ממושכים גיליתי שעלי להעביר אותו באמצעות מילת המפתח use (אני לא נכנסת כאן לפרטים יותר מדוייקים, אלא רק מציינת זאת כדי לחסוך זמן למי שזקוק לזה). וכך נראה הקוד:

$children_array = array_filter ( $termchildren , function($obj) use($child) { // pass $child as argument, otherwise it's not known in the context
    if ( $obj->parent == $child->term_id ) {
        return true;
    }
    return false;
} );

במקרה שאכן יש, הוספתי לפריט את menu-item-has-children.

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

זה נשמע קצת מסובך, אבל תכל’ס זה עושה מה שצריך:

/**
 * This function adds child categories to the menu items that are categories that have children.
 * Taken from http://teleogistic.net/2013/02/dynamically-add-items-to-a-wp_nav_menu-list/
 * */
function kamoha_menu_cat_subnav ( $items , $menu , $args ) {
    // Only do this in the topics menu
    if ( ! is_admin () ) {
    // loop thru the menu items, and find the ones that are categories
    $menu_order = count ( $items ) + 1;
    $is_archive = false;
    foreach ( $items as $item ) {
        if ( 'category' == $item->object ) {
        // check if item has child categories
        $args = 'child_of=' . $item->object_id . '&hierarchical=1'; /* the cat_id */
        $args .= kamoha_order_categories_by ();

        // get the correct id of parent - either existing item, or added item
        $termchildren = get_categories ( $args );

        if ( ! empty ( $termchildren ) ) {
        // if it has child categories, add them to the menu
            foreach ( $termchildren as $child ) {

            // first check if this item has children
            $children_array = array_filter ( $termchildren , function($obj) use($child) { // pass $child as argument, otherwise it's not known in the context
                if ( $obj->parent == $child->term_id ) {
                    return true;
                }
                return false;
            } );

            // then check if this item has parents in the array
            $parents_array = array_filter ( $termchildren , function($obj) use($child) { // pass $child as argument, otherwise it's not known in the context
                if ( $obj->term_id == $child->parent ) {
                    return true;
                }
                return false;
            } );

            // get the correct id of parent - either existing item, or added item
            $menu_item_parent = count ( $parents_array ) > 0 ? $child->parent : $item->ID;

            $new_item = wp_setup_nav_menu_item ( $child );
            $new_item->menu_item_parent = $menu_item_parent; /* the parent id should be the ID of the item in the menu, not the object_id which is the category id */
            $new_item->db_id = $child->term_id;
            $new_item->url = get_term_link ( $child );
            $new_item->title = $child->name;
            $new_item->menu_order = $menu_order;
            if ( count ( $children_array ) > 0 ) {
                $new_item->classes[] = 'menu-item-has-children';
            }
            $items[] = $new_item;
            $menu_order ++;
            }
          }
        }
      }
    }
    return $items;
}

add_filter ( 'wp_get_nav_menu_items' , 'kamoha_menu_cat_subnav' , 10 , 3 );

כפי שניתן לראות, עטפתי את הכל ב-if ( ! is_admin () ) מפני שאחרת כל זה קרה גם בניהול התפריט, וזה היה קצת מבלבל ובעיקר מיותר.

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

function finance_menu_add_attr ( $atts, $item, $args ) {

    if ( ! is_admin () ) {

        // loop thru the menu items, and attach the slide-number property
        if ( $item -> type == 'custom' ) {
            // get the number from the title
            $atts['data-slide'] = mb_substr ( $item -> title, mb_strlen ( __ ( 'slide', 'finance' ) ) );
        }
    }
    return $atts;
}

add_filter ( 'nav_menu_link_attributes', 'finance_menu_add_attr', 10, 3 );

וכך אפשר בקלות לשלוט על תפריטים בוורדפרס.

עדכון:

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

הדרך שבה בחרתי לעשות זאת היא להשתמש במשתנה ה-location של תפריט, כי למרבה השמחה יש שילוב פונקציות שיכול לתת לי את המידע הזה. ישנה הפונקציה get_nav_menu_locations שמחזירה מערך תפריטים שהאינדקס שלו הוא ה-locations של התפריט, וע”י הפונקציה get_term אני יכולה לקבל את התפריט הזה.

function motnet_get_nav_menu_items( $items, $menu, $args ){
    if ( ! is_admin() ) {
        // limit this function to hishtalmyuot_nav
        $menu_locations = get_nav_menu_locations();
        $hishtalmyuot_nav = get_term( $menu_locations['hishtalmyuot'], 'nav_menu' );
        if ( $hishtalmyuot_nav->term_id === $menu->term_id ) {
            ....
        }
    }
 return $items;
 }

מה אתם אומרים? האם יש לכם דרכים נוספות לעשות זאת?

6 תגובות על “תתי קטגוריות בתפריט וורדפרס

  1. איך ניתן להכניס פוסט למספר קטגוריות שונות בהקשה אחת?
    האם ניתן להעביר אוטומטית 5 פוסטים אחרונים לתחילת הרשימה מידי פרק זמן מוגדר?
    תודה

כתבו תגובה ללאה כהן Cancel reply

כתובת הדוא"ל שלכם לא תוצג.