← home

워드프레스 – Walker 클래스의 이해

Walker 클래스에 대해서 들어보신 적 있으신가요?
아니면 다음과 같은 템플릿 태그를 사용해보신 적은?
wp_nav_menu
wp_list_pages
wp_list_categories
위 템플릿 태그들의 공통점은 트리 구조의 데이터를 다룬다는 점과 Walker 클래스를 이용하여 트리 구조의 데이터를 HTML에 반영하여 화면에 나타낸다는 점입니다.

메뉴 아이템, 페이지, 카테고리와 같은 데이터들은 부모/자식/형제 관계를 가질 수 있습니다. 이러한 데이터를 가리켜 트리(또는 계층) 구조를 이루고 있다고 말합니다.
이러한 트리 구조의 데이터를 HTML에 반영하여 렌더링하자면… 머리가 좀 팽글팽글 돌곤 하지요. 재귀적으로 함수를 호출하는 작업을 하다보면 실수로 루프에 걸리기도 하고… 이유는 잘 모르겠지만, 개인적으로는 이런 종류의 작업을 할 때 피곤함을 많이 느낍니다.
Walker 클래스를 사용한다면, 머리가 팽글팽글 도는 부분. 즉, 데이터를 계층적으로 만들거나 트리의 각 노드를 추적하는 부분에 신경쓰지 않고, 마크업을 만드는 부분만 확장하여 원하는대로 만들어주면 됩니다.

Walker 클래스는 추상(abstract) 클래스로 설계되었기 때문에, 이 클래스를 사용하기 위해서는 반드시 확장(extended)해서 사용해야합니다. 간단한 예를 통해서 사용법을 살펴보도록 하겠습니다.
우선, 실습을 위해 아래와 같이 극단적(?)으로 단순한 데이터를 준비해보았습니다.

CREATE TABLE `wp_my_walker_dummy` (`ID` int(11) NOT NULL AUTO_INCREMENT, `parent_id` int(11) NOT NULL, `title` varchar(255) NOT NULL, PRIMARY KEY (`ID`));
INSERT INTO `wp_my_walker_dummy` (`ID`, `parent_id`, `title`) VALUES (1, 0, 'Item-1'), (2, 0, 'Item-2'), (3, 0, 'Item-3'), (5, 1, 'Item-1-1'), (6, 1, 'Item-1-2'), (7, 1, 'Item-1-3'), (8, 7, 'Item-1-3-1'), (9, 7, 'Item-1-3-2'), (10, 2, 'Item-2-1'), (11, 2, 'Item-2-2');

데이터 테이블만 보고도 그림이 머리에 그려지시나요? 미리 결과를 보여드리자면 아래와 같습니다.

그럼 실습을 시작해보겠습니다.

class Walker_Example extends Walker {
	var $db_fields = array( 'parent' => 'parent_id', 'id' => 'ID' );
}
$rows = $wpdb->get_results("SELECT * FROM wp_my_walker_dummy ORDER BY ID");
$walker = new Walker_Example;
echo '<ul>' . $walker->walk($rows, 0) . '</ul>';

라인 1: Walker 클래스를 확장합니다.
라인 2: $db_fields 멤버 변수는 필수입니다. 예를 들어, 페이지 오브젝트는 ID 필드와 post_parent 필드를 가지고 있습니다. 이 두 필드를 통해 종속관계를 판단할 수 있음을 잘 알고 계실텐데요, 그런데 Walker 클래스는 어떤 종류의 트리 오브젝트든지 사용될 수 있으므로, 오브젝트의 어떤 필드가 id이고 어떤 필드가 parent인지 그 필드의 키를 미리 정의해주어야 매칭이 가능할 것입니다. 따라서 실습중인 데이터의 id는 ID로 parent는 parent_id로 할당하였습니다.
라인 4: 데이터 가져오기
라인 5: 인스턴스 생성
라인 6: 워크 실행. 화면 출력. 그러나 화면에는 아무것도 나타나지 않을 것입니다. Walker 클래스가 기본적으로 데이터를 계층적으로 만들고, 트리의 각 노드를 추적하는 일을 수행하지만, 마크업을 만드는 부분은 확장해주어야 합니다.

마크업을 정의하는 확장 메서드는 4가지가 있습니다.
start_lvl 리스트 시작부분의 마크업. lvl은 level의 약자인 듯.
end_lvl 리스트 끝부분의 마크업.
start_el 요소 시작부분의 마크업. el은 element의 약자인 듯.
end_el 요소 마지막부분의 마크업.

class Walker_Example extends Walker {
	var $db_fields = array( 'parent' => 'parent_id', 'id' => 'ID' );

	function start_lvl(&$output, $depth = 0, $args = array()) {
		$output .= '<ul>';
	}

	function end_lvl(&$output, $depth = 0, $args = array()) {
		$output .= '</ul>';
	}

	function start_el( &$output, $item, $depth = 0, $args = array(), $current_object_id = 0 ) {
		$output .= '<li>' . $item->title;
	}

	function end_el(&$output, $item, $depth=0, $args=array()) {
		$output .= '</li>';
	}
}
$rows = $wpdb->get_results("SELECT * FROM wp_my_walker_dummy ORDER BY ID");
$walker = new Walker_Example;
echo '<ul>' . $walker->walk($rows, 0) . '</ul>';

라인 13: 실습에서는 간단히 아이템의 제목만 레퍼런스 변수에 더하였지만, 필요에 따라 li 에 클래스를 부여한다거나, 제목에 링크를 걸어줄 수 있을 것입니다.

대표적으로 wp_nav_menu을 이용하여 사이트 네비게이션을 만들때, Walker를 사용자정의해야하는 경우가 종종 있습니다. 다행히도 wp_nav_menu에 사용자정의 Walker를 매개변수로 전달할 수 있습니다. Walker에 대한 기본 이해만 있다면 손쉽게 확장할 수 있을 것입니다.

← home