저번에 만들었던 사이드바 중 왼쪽 사이드바는 네비게이션 역할을 합니다.
네비게이션 워커
이곳의 내용은 Wordpress Reference: Walker를 참고했습니다.
네비게이션은 워드프레스 내장함수인 wp_nav_menu()를 이용해서 불러올 수 있습니다. 하지만 원하는대로 꾸미기에는 무언가 부족한데요.
<?php
wp_nav_menu( array(
'walker' => new S0_Walker_Nav(),
) );
?>
워커(walker)라는 것을 따로 지정해서 원하는대로 꾸밀 수 있습니다. 새로운 워커를 만들 때 기존 워커인 Walker_Nav_Menu()를 상속받고 원하는 함수만 덧씌워서 사용할 수 있습니다. 네비게이션과 관련한 함수는 아래의 4가지가 있습니다.
<?php
class S0_Walker_Nav extends Walker_Nav_Menu {
function start_lvl( &$output, $depth = 0, $args = array() ) {
// 레벨을 시작할 때 (ul, ol, div 등)
}
function end_lvl( &$output, $depth = 0, $args = array() ) {
// 레벨을 끝낼 때
}
function start_el( &$output, $item, $depth=0, $args=array(), $id=0 ) {
// 요소를 시작할 때
}
function end_el( &$output, $object, $depth = 0, $args = array() ) {
// 요소를 끝낼 때
}
}
?>
원본의 내용을 확인하고 싶다면 워드프레스 설치 디렉토리에서 /wp-includes/class-walker-nav-menu.php파일을 찾아 열어보면 됩니다.
클래스
네비게이션 요소의 특성은 클래스로 구분됩니다. start_el과 end_el에서 클래스 목록을 얻을 수 있습니다.
<?php
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$classes = apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth );
?>
menu-item: 모든 요소에 이 클래스가 들어갑니다.menu-item-object-post: 포스트 요소입니다.menu-item-object-custom: 직접 지정한 하이퍼링크입니다.menu-item-object-page: 페이지 요소입니다.menu-item-object-category: 카테고리 요소입니다.front-item: 최상위 요소입니다sub-item: 하위 요소입니다.menu-item-has-children: 요소에 자식(하위요소)가 있는 경우입니다.current-menu-item: 선택한 요소입니다.current-menu-parent: 선택한 요소의 부모입니다.current-menu-ancestor: 선택한 메뉴의 조상입니다.
구조
네비게이션의 요소와 구조가 다음과 같을 때,
- 메뉴 1
- 메뉴 2
- 메뉴 2-1
- 메뉴 2-2
네비게이션 워커는 다음과 같은 방식으로 동작합니다.
<?php
/**
* 네비게이션 워커 시작
*/
start_el(...); // 메뉴 1
end_el(...); // 메뉴 1
start_el(...); // 메뉴 2
start_lvl(...); // 레벨 2
start_el(...); // 메뉴 2-1
end_el(...); // 메뉴 2-1
start_el(...); // 메뉴 2-2
end_el(...); // 메뉴 2-2
end_lvl(...); // 레벨 2
end_el(...); // 메뉴 2
/**
* 네비게이션 워커 끝
*/
?>
예시
<?php
class S0_Walker_Nav extends Walker_Nav_Menu {
}
function.php에 클래스를 하나 만듭니다. 이 클래스는 워드프레스의 내부 클래스인 Walker_Nav_Menu를 상속받습니다.
public function start_lvl( &$output, $depth = 0, $args = array() ) {
$classes = array( 'sub-menu', "sub-menu-$depth" );
$class_names = join( ' ', apply_filters( 'nav_menu_submenu_css_class', $classes, $args, $depth ) );
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
$output .= "<ul$class_names>";
}
public function end_lvl( &$output, $depth = 0, $args = array() ) {
$output .= "</ul> <!-- sub-menu-$depth -->";
}
S0_Walker_Nav클래스의 레벨 함수입니다. start_lvl과 end_lvl은 서브메뉴가 만들어 질 때에 작동합니다. 모든 메뉴를 감싸는 요소는 wp_nav_menu()의 컨테이너(container)속성으로 제어할 수 있습니다.
function start_el( &$output, $item, $depth=0, $args=array(), $id=0 ) {
요소를 시작할 때 작동하는 함수인 start_el은 내용이 많아서 기능에 따라 몇 구간으로 나눠서 살펴보겠습니다.
$args = apply_filters( 'nav_menu_item_args', $args, $item, $depth );
$args는 특정 아이템에 어떤 속성이 있을 때 반영하기 위한 변수입니다.
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$classes = apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth );
$classes[] = ( $depth ) ? 'sub-item' : 'front-item';
$class_names = join( ' ', $classes );
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
$output .= '<li' . $class_names .'>';
$classes에는 클래스를 배열 형태로 저장합니다. $class_names는 <li>태그의 클래스 속성을 담은 문자열입니다. 앞서 다룬 클래스들이 $classes에 들어가므로 요소의 종류에 따라 특별한 처리가 필요하다면 이것을 적극적으로 활용하는 것이 좋습니다.
$atts = array();
$atts['title'] = ! empty( $item->attr_title ) ? $item->attr_title : '';
$atts['target'] = ! empty( $item->target ) ? $item->target : '';
$atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : '';
$atts['href'] = ! empty( $item->url ) ? $item->url : '';
$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );
$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( ! empty( $value ) ) {
$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
$attributes .= ' ' . $attr . '="' . $value . '"';
}
}
메뉴에 접근하기 위한 하이퍼링크 <a>의 속성을 받아오는 부분입니다. $atts에는 키와 값으로 이루어져 있는 배열로 속성이 들어가 있으며, $attributes에는 속성이 문자열로 들어가 있습니다.
$title = apply_filters( 'the_title', $item->title, $item->ID );
$title = apply_filters( 'nav_menu_item_title', $title, $item, $args, $depth );
하이퍼링크의 텍스트 부분입니다. 뒤에 <a>$title</a>의 형태로 출력됩니다.
$item_output = $args->before;
$item_output .= '<a'. $attributes .'>';
$item_output .= $args->link_before . $title . $args->link_after;
$item_output .= '</a>';
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
최종 결과를 $output에 추가합니다. $item_output은 요소 전후에 들어갈 내용, 링크텍스트 전후에 들어갈 부분을 속성으로부터 받아오고, 요소의 내용을 채웁니다.
function end_el( &$output, $item, $depth = 0, $args = array() ) {
$output .= "</li>";
}
end_el은 요소를 닫습니다.
출력

전체 코드
functions.php
<?php
register_nav_menus( array(
'nav-menu' => __( 'Nav Menu' ),
) );
functions.php 혹은 다른 php파일로 만들어 추가합니다.
<?php
class S0_Walker_Nav extends Walker_Nav_Menu {
public function start_lvl( &$output, $depth = 0, $args = array() ) {
$classes = array( 'sub-menu', "sub-menu-$depth" );
$class_names = join( ' ', apply_filters( 'nav_menu_submenu_css_class', $classes, $args, $depth ) );
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
$output .= "<ul$class_names>";
}
public function end_lvl( &$output, $depth = 0, $args = array() ) {
$output .= "</ul> <!-- sub-menu-$depth -->";
}
function start_el( &$output, $item, $depth=0, $args=array(), $id=0 ) {
$args = apply_filters( 'nav_menu_item_args', $args, $item, $depth );
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$classes = apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth );
$classes[] = ( $depth ) ? 'sub-item' : 'front-item';
$class_names = join( ' ', $classes );
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
$output .= '<li' . $class_names .'>';
$atts = array();
$atts['title'] = ! empty( $item->attr_title ) ? $item->attr_title : '';
$atts['target'] = ! empty( $item->target ) ? $item->target : '';
$atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : '';
$atts['href'] = ! empty( $item->url ) ? $item->url : '';
$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );
$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( ! empty( $value ) ) {
$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
$attributes .= ' ' . $attr . '="' . $value . '"';
}
}
$title = apply_filters( 'the_title', $item->title, $item->ID );
$title = apply_filters( 'nav_menu_item_title', $title, $item, $args, $depth );
$item_output = $args->before;
$item_output .= '<a'. $attributes .'>';
$item_output .= $args->link_before . $title . $args->link_after;
$item_output .= '</a>';
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
function end_el( &$output, $item, $depth = 0, $args = array() ) {
$output .= "</li>";
}
}
sidebar.php 원하는 부분에 다음 내용을 추가합니다.
<?php
wp_nav_menu(array(
'menu' => 'nav-menu',
'theme_location' => 'nav-menu',
'container' => 'ul',
'walker' => new S0_Walker_Nav(),
) );
?>
내용이 길어져서 필요한 몇 가지 기능을 붙이는 작업은 다음에 다루기로 하겠습니다.