남의 코드가 하는 일이 우리와 충돌할 때, 필터로 덮어쓰는 것보다 아예 내리는 편이 정직할 때가 있습니다. 부모 테마를 고치지 않고도 그 테마의 특정 출력만 없앨 수 있다는 것이 훅 설계의 큰 이점입니다.
다만 remove_action() 과 remove_filter() 는 실패해도 예외를 던지지 않습니다. false 를 돌려주고 끝이고, 그래서 안 내려간 것과 애초에 없던 것이 구분되지 않습니다.
세 가지가 정확히 같아야 합니다
우선순위가 가장 자주 어긋납니다. 등록과 제거 양쪽 다 기본값 10을 쓰면 그냥 되기 때문에 “우선순위는 안 적어도 되는 것” 으로 굳어지는데, 상대가 20에 걸었다면 10으로는 절대 내려가지 않습니다. 숫자를 반드시 확인합니다.
시점도 흔합니다. 아직 등록되지 않은 것은 내릴 수 없습니다. 상대가 init 에서 등록한다면 우리 제거는 init 의 더 늦은 우선순위나 wp_loaded 에서 돌아야 합니다.
add_action( 'after_setup_theme', function () {
$ok = remove_action( 'kalium_wrapper_start', 'kalium_page_heading_title_display', 20 );
// $ok 가 false 면 이름 · 우선순위 · 시점 중 하나가 틀렸다는 뜻이다.
// 실패를 조용히 넘기지 않는다.
} );
내리려는 것이 무엇인지에 따라 식별자가 다릅니다
일반 함수는 이름 문자열 그대로입니다. 정적 메서드는 [ 'Some_Class', 'method' ] 또는 'Some_Class::method' 로 지정합니다.
인스턴스 메서드는 같은 객체가 필요합니다. 등록에 쓰인 그 인스턴스를 손에 넣을 수 없으면 내릴 수 없습니다. 싱글턴이라면 접근자가 있어 가능하지만, 생성자 안에서 자기를 등록하고 참조를 남기지 않는 구조라면 방법이 없습니다.
클로저는 이름으로 내릴 수 없습니다. 참조할 손잡이가 없기 때문입니다. 이것은 결함이 아니라 설계의 귀결이고, 그래서 플러그인을 만드는 쪽에 규칙이 생깁니다 — 남이 조정할 수 있어야 하는 훅에는 클로저를 걸지 말고 이름 있는 함수나 공개된 인스턴스의 메서드를 씁니다. 클로저는 아무도 건드릴 이유가 없는 내부 배선에만 씁니다.
내리는 자리가 훅 안이라는 함정
등록이 어느 훅 안에서 일어나는지도 봐야 합니다. 이 저장소에서 부모 테마의 프론트 스크립트를 걷어낼 때 겪은 것입니다. 그 스크립트는 wp_footer 안에서 등록되고 있었습니다 — 즉 wp_head 시점에 대기열에서 빼려 해도 그때는 아직 대기열에 없습니다.
해결은 스크립트를 빼는 것이 아니라 등록하는 액션 자체를 내리는 것이었습니다. “무엇을 내릴 것인가” 를 한 단계 위에서 다시 보는 것이 이런 경우의 답입니다.
그리고 내린 뒤에는 무엇이 함께 사라졌는지 확인합니다. 같은 콜백이 우리가 모르는 다른 일도 하고 있었을 수 있습니다. 실제 작업에서 이 확인을 어떻게 하는지는 작업 과정에 절차로 공개돼 있고, 관련 글은 개발 워크플로우 아카이브에 있습니다.
다음 회차
지금까지는 남이 남긴 확장 지점을 쓰는 이야기였습니다. 다음 회차는 반대편입니다 — 우리 코드에 훅을 남겨, 남이 우리 파일을 고치지 않고도 바꿀 수 있게 만드는 설계입니다.