워드프레스가 오랫동안 확장되어 온 이유는 훅입니다. 코어 파일을 고치지 않고, 테마를 포크하지 않고, 남의 플러그인을 건드리지 않고도 동작을 바꿀 수 있습니다. 덕분에 업데이트가 우리 수정을 덮어쓰지 않습니다 — 확장과 업데이트가 서로를 막지 않는다는 것은 흔한 설계가 아닙니다.
훅은 두 종류뿐입니다. 액션과 필터. 차이는 하나입니다 — 값을 돌려주느냐.
액션은 일을 하고, 필터는 값을 바꿉니다
액션은 “이 시점에 무언가를 해라” 입니다. 출력하고, 저장하고, 메일을 보냅니다. 돌려줄 값이 없고, 돌려줘도 아무도 받지 않습니다.
필터는 “이 값을 받아 바꿔서 돌려줘라” 입니다. 워드프레스는 apply_filters() 가 돌려준 것을 그대로 씁니다. 그래서 반환이 계약입니다.
// 액션 — 일을 한다. 반환값은 쓰이지 않는다.
add_action( 'wp_footer', 'wper_footer_note' );
function wper_footer_note() {
echo '<p class="note">문의는 언제든 주세요.</p>';
}
// 필터 — 값을 받아 바꿔서 돌려준다. 반환이 없으면 계약 위반이다.
add_filter( 'excerpt_length', 'wper_excerpt_length' );
function wper_excerpt_length( $length ) {
return 30;
}
내부를 보면 add_action() 은 add_filter() 를 그대로 부르고, 두 등록이 같은 전역 등록부에 쌓입니다. 등록 구조는 하나이고 반환값을 쓰느냐 버리느냐만 다릅니다. 이름이 둘인 이유는 기계가 아니라 읽는 사람을 위한 것입니다 — 함수 이름만 보고도 “이건 값을 돌려줘야 하는구나” 를 알 수 있게.
반환을 빠뜨리면 값이 조용히 사라집니다
필터 콜백에서 return 을 빠뜨리면 PHP 는 null 을 돌려줍니다. 에러도 경고도 나지 않습니다. 그 null 이 다음 콜백에 그대로 전달되고, 최종적으로 화면에 빈 값이 나갑니다.
// 조건 분기 하나에만 return 이 있는, 아주 흔한 형태
add_filter( 'the_title', 'wper_clean_title' );
function wper_clean_title( $title ) {
if ( is_admin() ) {
return $title;
}
$title = trim( $title ); // 여기서 함수가 끝난다 → null 이 돌아간다
}
증상이 고약합니다. 관리자 화면에서는 제목이 멀쩡히 보이고(위 분기에 return 이 있으므로) 프론트에서만 제목이 사라집니다. 그래서 원인을 템플릿이나 테마에서 찾게 됩니다.
인자는 선언한 개수만큼만 옵니다
add_filter() 의 네 번째 인자는 받을 인자 개수이고 기본값은 1입니다. 필터가 인자 세 개를 넘겨 주더라도 선언하지 않으면 첫 번째만 도착합니다.
// 2 를 선언해야 $post_id 가 온다. 빠뜨리면 그 자리에 아무것도 오지 않는다.
add_filter( 'the_title', 'wper_tag_title', 10, 2 );
function wper_tag_title( $title, $post_id ) {
return $title;
}
세 번째 인자는 우선순위입니다. 여기서는 기본값 10을 그대로 씁니다 — 우선순위를 언제 조정해야 하고 왜 그것이 영구적인 해결이 아닌지는 3회차에서 따로 다룹니다.
훅을 전제로 한 개발 습관 전반은 개발 워크플로우 아카이브에 모여 있고, 남이 만든 테마와 플러그인 위에서 이 원칙을 지키며 손보는 실제 절차는 작업 과정에 공개돼 있습니다.
다음 회차
훅을 올바르게 골랐어도 거는 시점이 틀리면 아무 일도 일어나지 않습니다. 다음 회차는 init 보다 이른 곳에서 하면 안 되는 일들입니다 — 번역이 조용히 빠지는 사고가 여기서 나옵니다.