4th Street Bar Hive-Bar

Hive-Bar Powered by Hive beta-fdb5b5b

Community post

워드프레스 테마 만들기: 사이드 네비게이션 (1)

저번에 만들었던 사이드바 중 왼쪽 사이드바는 네비게이션 역할을 합니다.

네비게이션 워커

이곳의 내용은 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_elend_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_lvlend_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은 요소를 닫습니다.

출력

soma0sd.local_.png

전체 코드

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,output,depth = 0, $args = array() ) {
    classes=array('sub-menu',"sub-menu-classes = array( 'sub-menu', "sub-menu-depth" );
    classnames=join('',applyfilters('navmenusubmenucssclass',class_names = join( ' ', apply_filters( 'nav_menu_submenu_css_class',classes, args,args,depth ) );
    classnames=class_names =class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
    output.="<uloutput .= "<ulclass_names>";
  }
  public function end_lvl( &output,output,depth = 0, $args = array() ) {
    output.="</ul><!--sub-menu-output .= "</ul> <!-- sub-menu-depth -->";
  }

  function start_el( &output,output,item, depth=0,depth=0,args=array(), $id=0 ) {
    args=applyfilters('navmenuitemargs',args = apply_filters( 'nav_menu_item_args',args, item,item,depth );

		classes=empty(classes = empty(item->classes ) ? array() : (array) $item->classes;
    classes=applyfilters('navmenucssclass',arrayfilter(classes = apply_filters( 'nav_menu_css_class', array_filter(classes ), item,item,args, $depth );
    classes[]=(classes[] = (depth ) ? 'sub-item' : 'front-item';

		classnames=join('',class_names = join( ' ',classes );
		classnames=class_names =class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';

		output.='<li'.output .= '<li' .class_names .'>';

		$atts = array();
		atts['title']=!empty(atts['title']  = ! empty(item->attr_title ) ? $item->attr_title : '';
		atts['target']=!empty(atts['target'] = ! empty(item->target )     ? $item->target     : '';
		atts['rel']=!empty(atts['rel']    = ! empty(item->xfn )        ? $item->xfn        : '';
		atts['href']=!empty(atts['href']   = ! empty(item->url )        ? $item->url        : '';

		atts=applyfilters('navmenulinkattributes',atts = apply_filters( 'nav_menu_link_attributes',atts, item,item,args, $depth );

		$attributes = '';
		foreach ( attsasatts asattr => $value ) {
			if ( ! empty( $value ) ) {
				value=('href'===value = ( 'href' ===attr ) ? esc_url( value):escattr(value ) : esc_attr(value );
				attributes.=''.attributes .= ' ' .attr . '="' . $value . '"';
			}
		}

		title=applyfilters('thetitle',title = apply_filters( 'the_title',item->title, $item->ID );

		title=applyfilters('navmenuitemtitle',title = apply_filters( 'nav_menu_item_title',title, item,item,args, $depth );

		itemoutput=item_output =args->before;
    itemoutput.='<a'.item_output .= '<a'.attributes .'>';
		itemoutput.=item_output .=args->link_before . title.title .args->link_after;
		$item_output .= '</a>';
		itemoutput.=item_output .=args->after;

		output.=applyfilters('walkernavmenustartel',output .= apply_filters( 'walker_nav_menu_start_el',item_output, item,item,depth, $args );
  }

  function end_el( &output,output,item, depth=0,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(),
) );
?>

내용이 길어져서 필요한 몇 가지 기능을 붙이는 작업은 다음에 다루기로 하겠습니다.

4 upvotes $1.23

Replies (4)

Review before signing

Posting as . Signing with . Keychain permission: Posting. Hive Keychain will ask you to approve this action next.


  
Technical details

Operation fingerprint: