WordPress 훅 색인
개발자가 실제로 사용하는 WordPress 액션과 필터를 검색할 수 있는 색인 — 정확한 add_action/add_filter 시그니처, 실행 시점, 동작하는 예제, 그리고 사람들이 흔히 당하는 함정까지 담았습니다.
39개의 훅을 정확한 add_action / add_filter 시그니처, 실행 시점, 실제로 동작하는 예제, 그리고 사람들이 흔히 걸려 넘어지는 지점과 함께 정리했습니다. 그중 1개는 미검증으로 표시되어 있습니다 — 인자 개수를 WordPress 소스와 대조해 확인하지 않았으며, 추측을 사실인 양 내놓기보다는 그 점을 분명히 밝히는 편을 택했습니다.
이 목록은 전부를 담지도 않았고 그런 척하지도 않습니다 — WordPress에는 수천 개의 훅이 있습니다. 여기서는 사람들이 실제로 자주 찾는 훅을 다룹니다.
WordPress 로딩이 끝난 뒤, 헤더가 전송되기 전에 실행됩니다. 커스텀 포스트 타입, 분류(taxonomy), 리라이트 규칙을 등록하는 표준 위치입니다.
실행 시점
코어, 플러그인, 테마가 로드된 뒤 프런트엔드와 관리자 양쪽 모든 요청에서 실행됩니다.
시그니처
add_action( 'init', 'my_callback' );예제
add_action( 'init', function () {
register_post_type( 'book', array(
'public' => true,
'label' => 'Books',
'show_in_rest' => true, // required for the block editor
) );
} );주의할 점
init은 AJAX, REST, cron을 포함한 모든 요청에서 실행됩니다. 여기서 느린 작업(HTTP 요청, 무거운 쿼리)을 하면 모든 페이지 로드에 부담을 줍니다. 또한 여기서는 현재 사용자에 접근할 수 있지만, 아무것도 출력해서는 안 됩니다 — 헤더가 아직 전송되지 않았지만 곧 전송될 참이기 때문입니다.
테마가 로드되면 한 번 실행됩니다. add_theme_support(), add_image_size() 호출과 내비게이션 메뉴 등록에 알맞은 위치입니다.
실행 시점
테마의 functions.php가 로드된 후, init 이전에 실행됩니다.
시그니처
add_action( 'after_setup_theme', 'my_callback' );예제
add_action( 'after_setup_theme', function () {
add_theme_support( 'post-thumbnails' );
add_theme_support( 'title-tag' );
add_image_size( 'card', 600, 400, true ); // true = hard crop
} );주의할 점
이미지 크기를 여기가 아니라 init에서 등록하면 대부분은 어쩌다 동작하지만 어떤 경우에는 원인 모르게 실패합니다. after_setup_theme을 사용하세요 — 바로 그 용도의 훅입니다.
활성화된 모든 플러그인이 로드되면 한 번 실행됩니다. 다른 플러그인과 상호작용할 수 있는 가장 이른 안전 지점입니다.
실행 시점
모든 플러그인 파일이 포함된 후, 테마가 로드되기 전에 실행됩니다.
시그니처
add_action( 'plugins_loaded', 'my_callback' );주의할 점
여기서는 현재 사용자에 아직 접근할 수 없습니다 — wp_get_current_user()가 안정적으로 동작하지 않습니다. 사용자가 필요하면 init을 사용하세요.
WordPress가 완전히 로드된 후 실행됩니다 — 플러그인, 테마, init, 사용자가 모두 준비된 상태입니다.
실행 시점
init 이후, 그리고 현재 사용자가 설정된 후에 실행됩니다.
시그니처
add_action( 'wp_loaded', 'my_callback' );모든 관리자 요청의 시작 시점에 실행됩니다. register_setting(), 권한 확인, 관리자 리디렉션에 사용됩니다.
실행 시점
모든 관리자 측 요청에서 실행됩니다.
시그니처
add_action( 'admin_init', 'my_callback' );주의할 점
이 훅은 실제 "관리자 화면"이 아닌 admin-ajax.php 요청에서도 실행됩니다. 콜백이 화면의 존재를 전제한다면 wp_doing_ajax()로 방어하세요.
프런트엔드 CSS와 JavaScript를 등록(enqueue)하는 유일하게 올바른 위치입니다.
실행 시점
프런트엔드 페이지 로드 시, head가 렌더링되기 전에 실행됩니다.
시그니처
add_action( 'wp_enqueue_scripts', 'my_callback' );예제
add_action( 'wp_enqueue_scripts', function () {
wp_enqueue_style(
'child-style',
get_stylesheet_uri(),
array( 'parent-style' ), // load AFTER the parent
wp_get_theme()->get( 'Version' ) // cache-bust on version change
);
} );주의할 점
이름과 달리 스크립트뿐 아니라 스타일도 처리합니다 — wp_enqueue_styles 훅은 존재하지 않으며, 사람들이 그것을 찾느라 실제로 시간을 낭비합니다. 또한 이 훅은 관리자(admin_enqueue_scripts 사용)나 블록 편집기(enqueue_block_editor_assets 사용)에서는 실행되지 않습니다.
관리자에서 CSS/JS를 등록합니다. 현재 화면의 훅 접미사(hook suffix)를 전달받으므로 특정 화면에서만 에셋을 로드할 수 있습니다.
실행 시점
관리자 페이지 로드 시 실행됩니다.
시그니처
add_action( 'admin_enqueue_scripts', 'my_callback' ); // receives $hook_suffix예제
add_action( 'admin_enqueue_scripts', function ( $hook ) {
if ( 'settings_page_my-plugin' !== $hook ) {
return; // do not load our JS on every admin screen
}
wp_enqueue_script( 'my-admin', plugins_url( 'admin.js', __FILE__ ), array(), '1.0', true );
} );주의할 점
$hook으로 방어하지 않는 것이 플러그인이 무관한 관리자 화면을 망가뜨리는 가장 흔한 원인입니다. 에셋은 필요한 곳에서만 로드하고 그 외에는 로드하지 마세요.
에셋을 블록 편집기(Gutenberg)에만 등록합니다 — 프런트엔드도, 나머지 관리자 화면도 아닙니다.
실행 시점
블록 편집기가 로드될 때 실행됩니다.
시그니처
add_action( 'enqueue_block_editor_assets', 'my_callback' );<head> 안에 출력을 인쇄합니다. 메타 태그와 인라인 크리티컬 CSS에 사용됩니다.
실행 시점
프런트엔드의 <head> 내부에서 실행됩니다.
시그니처
add_action( 'wp_head', 'my_callback' );주의할 점
여기서 스크립트나 스타일을 등록하지 마세요 — 의존성과 중복 제거를 WordPress가 처리하도록 wp_enqueue_scripts를 사용하세요. wp_head에 <script> 태그를 직접 출력하면 그 모든 처리를 건너뛰게 되며, 그래서 수많은 사이트가 jQuery를 세 번씩 로드하는 것입니다.
</body> 바로 앞에 출력을 인쇄합니다. 애널리틱스 스니펫과 지연 마크업에 알맞은 위치입니다.
실행 시점
프런트엔드 페이지의 끝에서 실행됩니다.
시그니처
add_action( 'wp_footer', 'my_callback' );주의할 점
wp_footer() 호출을 빠뜨린 테마는 관리자 바를 망가뜨리고, 푸터 스크립트를 등록하는 모든 플러그인을 망가뜨리며, wordpress.org 테마 심사에서 자동으로 탈락합니다.
게시물 내용이 표시되기 직전에 필터링합니다. 게시물에 마크업을 앞이나 뒤에 덧붙이는 일반적인 위치입니다.
실행 시점
the_content()가 호출될 때마다 실행됩니다.
시그니처
add_filter( 'the_content', 'my_callback' ); // receives $content예제
add_filter( 'the_content', function ( $content ) {
if ( ! is_singular( 'post' ) || ! in_the_loop() || ! is_main_query() ) {
return $content; // <- the guard everyone forgets
}
return $content . '<p class="cta">Enjoyed this? Read more.</p>';
} );주의할 점
이 필터는 생각보다 훨씬 자주 실행됩니다 — 위젯에서, REST 응답에서, 일부 플러그인의 요약 생성에서, 그리고 아카이브 루프에서는 게시물마다 한 번씩 실행됩니다. is_singular / in_the_loop / is_main_query 방어 없이는 CTA가 블로그 인덱스와 RSS 피드 안에 열다섯 번씩 나타납니다. WordPress에서 가장 오용되는 필터입니다.
표시 전에 게시물 제목을 필터링합니다.
실행 시점
the_title() 또는 get_the_title()이 호출될 때마다 실행됩니다.
시그니처
add_filter( 'the_title', 'my_callback', 10, 2 ); // receives $title, $post_id주의할 점
이 훅은 관리자 메뉴, 내비게이션 메뉴, 문서 <title>의 제목에도 적용됩니다. 조건 없이 필터링하면 의도하지 않은 곳의 이름까지 바뀝니다.
자동 생성 요약에 포함되는 단어 수를 설정합니다. 기본값은 55입니다.
실행 시점
수동 요약이 없는 게시물에 대해 WordPress가 요약을 생성할 때 실행됩니다.
시그니처
add_filter( 'excerpt_length', 'my_callback' ); // receives $length (words)예제
add_filter( 'excerpt_length', function ( $length ) {
return 25;
}, 999 ); // high priority: many themes set this too, and last one wins주의할 점
수동 요약이 있는 게시물에는 아무 효과가 없습니다 — 그런 요약은 그대로 사용됩니다. 또한 많은 테마가 이 필터를 직접 설정하므로, 우선순위 싸움에서 이기려면 높은 우선순위 번호가 필요할 때가 많습니다.
잘린 요약 뒤에 덧붙는 문자열을 변경합니다. 기본값은 " […]"입니다.
실행 시점
자동 생성 요약이 잘릴 때 실행됩니다.
시그니처
add_filter( 'excerpt_more', 'my_callback' ); // receives $more쿼리가 실행되기 전에 수정합니다. 아카이브에 표시되는 내용을 바꾸는 올바른 방법으로, 두 번째 WP_Query를 만드는 것보다 훨씬 낫습니다.
실행 시점
쿼리 변수가 파싱된 후, SQL이 구성되기 전에 실행됩니다.
시그니처
add_action( 'pre_get_posts', 'my_callback' ); // receives WP_Query $query (by reference)예제
add_action( 'pre_get_posts', function ( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return; // <- both guards are mandatory
}
if ( $query->is_category() ) {
$query->set( 'posts_per_page', 12 );
}
} );주의할 점
이 훅은 관리자에서도 실행되며, 메뉴·위젯·미디어 라이브러리를 포함한 모든 쿼리에서 실행됩니다. is_admin()과 is_main_query() 방어를 빠뜨리면 관리자 게시물 목록에 표시되는 내용이 조용히 바뀝니다 — 원인을 추적하기가 정말 어려운 버그입니다. 또한 주의하세요: 값을 반환하지 말고 $query를 수정하세요.
쿼리의 원시 SQL WHERE 절을 필터링합니다.
실행 시점
쿼리 SQL이 조립되는 동안 실행됩니다.
시그니처
add_filter( 'posts_where', 'my_callback', 10, 2 ); // receives $where, WP_Query $query주의할 점
원시 SQL을 작성하게 됩니다. 항상 $query->is_main_query()로 방어하고, 사용자 입력에는 항상 $wpdb->prepare()를 사용하세요. 이것은 WordPress 사이트에 SQL 인젝션을 끌어들이는 가장 빠른 길입니다.
쿼리가 찾은 전체 게시물 수를 필터링합니다 — 페이지네이션이 이 값을 기준으로 계산됩니다.
실행 시점
쿼리가 실행된 후, 페이지네이션이 계산되기 전에 실행됩니다.
시그니처
add_filter( 'found_posts', 'my_callback', 10, 2 ); // receives $found_posts, WP_Query $queryWordPress가 업로드 이미지를 축소해 원본 대신 "-scaled" 사본을 제공하기 시작하는 픽셀 크기를 설정합니다. 기본값은 2560입니다.
실행 시점
업로드 시, WordPress가 이미지가 "큰지" 판단할 때 실행됩니다.
시그니처
add_filter( 'big_image_size_threshold', 'my_callback' ); // receives int $threshold예제
// Serve originals at full resolution — no -scaled copy.
add_filter( 'big_image_size_threshold', '__return_false' );
// Or just raise the ceiling:
add_filter( 'big_image_size_threshold', function () {
return 3840;
} );주의할 점
이것이 "WordPress에 업로드한 뒤 이미지가 흐릿해 보인다"는 문제의 가장 흔한 원인인데, 이런 것이 있다는 걸 아는 사람이 거의 없습니다. 원본은 여전히 디스크에 있습니다 — 단지 절대 제공되지 않을 뿐입니다. 이 값은 가장 긴 변에 적용되며, 필터가 활성화된 이후 업로드된 이미지에만 영향을 준다는 점에 유의하세요.
WordPress가 업로드에 대해 생성하려는 이미지 크기 배열을 필터링합니다. 생성을 막으려면 해당 크기를 unset하세요.
실행 시점
업로드 시, 파생 파일이 생성되기 전에 실행됩니다.
시그니처
add_filter( 'intermediate_image_sizes_advanced', 'my_callback', 10, 2 ); // receives $sizes, $metadata예제
add_filter( 'intermediate_image_sizes_advanced', function ( $sizes ) {
unset( $sizes['1536x1536'] );
unset( $sizes['2048x2048'] );
return $sizes;
} );주의할 점
테마가 실제로 사용하는 크기를 제거하면 WordPress가 원본 전체 크기로 대체하게 되는데 — 이는 절약한 디스크 공간보다 더 나쁜 결과입니다. 그리고 이것은 새 파일 생성만 막을 뿐, 기존 파일은 다시 생성하기 전까지 그대로 남습니다.
WordPress가 업로드 이미지를 재인코딩할 때의 JPEG 품질을 설정합니다. 기본값은 82입니다.
실행 시점
WordPress가 JPEG를 기록할 때마다 실행됩니다.
시그니처
add_filter( 'jpeg_quality', 'my_callback', 10, 2 ); // receives $quality, $context주의할 점
품질 82는 사진에는 괜찮지만 스크린샷, 로고, 평면 그래픽에는 눈에 띄게 나쁩니다 — 그런 이미지는 가장자리가 뚜렷하고 아티팩트를 감출 사진 노이즈가 없기 때문입니다. 또한 wp_editor_set_quality가 더 현대적인 필터로, 이미지 편집기 클래스를 직접 다룹니다. 둘 다 설정하는 경우가 흔합니다.
WP_Image_Editor 클래스(GD 및 Imagick)가 사용하는 출력 품질을 설정합니다.
실행 시점
이미지 편집기 인스턴스가 품질을 설정할 때 실행됩니다.
시그니처
add_filter( 'wp_editor_set_quality', 'my_callback', 10, 2 ); // receives $quality, $mime_type커스텀 이미지 크기를 미디어 모달과 블록 편집기의 크기 드롭다운에 추가합니다.
실행 시점
미디어 UI가 크기 선택기를 구성할 때 실행됩니다.
시그니처
add_filter( 'image_size_names_choose', 'my_callback' ); // receives $sizes예제
add_filter( 'image_size_names_choose', function ( $sizes ) {
return array_merge( $sizes, array( 'card' => __( 'Card', 'textdomain' ) ) );
} );주의할 점
add_image_size()는 크기를 등록하지만 편집기에서 선택 가능하게 만들지는 않습니다. "커스텀 이미지 크기가 드롭다운에 나타나지 않는다"는 모든 질문은 이 필터가 빠진 경우입니다.
파일이 업로드 폴더로 옮겨지기 전에 검사하거나 거부합니다.
실행 시점
업로드 중, 파일이 기록되기 전에 실행됩니다.
시그니처
add_filter( 'wp_handle_upload_prefilter', 'my_callback' ); // receives $file주의할 점
파일을 거부하려면 $file['error']에 메시지 문자열을 설정하고 $file을 반환하세요. false를 반환하거나 예외를 던지는 것으로는 원하는 동작이 되지 않습니다.
첨부 파일이 처리된 후 (생성된 크기를 포함한) 메타데이터 배열을 필터링합니다.
실행 시점
업로드 시 파생 이미지가 생성된 후에 실행됩니다.
시그니처
add_filter( 'wp_generate_attachment_metadata', 'my_callback', 10, 2 ); // receives $metadata, $attachment_id주의할 점
이미지 최적화 플러그인이 사용하는 훅입니다. 느릴 수 있습니다 — 모든 이미지 크기가 기록된 후 실행되므로, 여기서 HTTP 요청을 하면 모든 업로드가 그것을 기다리게 됩니다.
WordPress가 반응형 이미지를 위해 생성하는 srcset 후보를 필터링합니다.
실행 시점
반응형 이미지가 렌더링될 때 실행됩니다.
시그니처
add_filter( 'wp_calculate_image_srcset', 'my_callback', 10, 5 );주의할 점
Removing the medium_large (768w) size elsewhere silently degrades srcset — that size exists almost entirely to serve it.
이 훅의 정확한 인자 개수를 WordPress 소스와 대조해 검증하지 않았습니다. 이 정보에 의존하기 전에 developer.wordpress.org에서 확인하세요. 불확실한 점을 조용히 덮고 추측을 사실인 양 내놓기보다는 그 점을 분명히 밝히는 편을 택했습니다.
관리자 메뉴와 하위 메뉴 페이지를 등록합니다.
실행 시점
관리자 메뉴가 구성될 때 실행됩니다.
시그니처
add_action( 'admin_menu', 'my_callback' );예제
add_action( 'admin_menu', function () {
add_options_page(
'My Plugin',
'My Plugin',
'manage_options', // capability — NOT a role
'my-plugin',
'my_render_settings_page'
);
} );주의할 점
capability 인자는 역할(role)이 아니라 권한(capability)입니다. "administrator"를 전달하면 동작하는 것처럼 보이지만(일부 설정에서는 관리자가 그 이름의 권한을 갖기 때문), 조용히 엉뚱한 사람들에게 접근 권한을 부여하게 됩니다. manage_options를 사용하세요.
관리자 화면 상단에 알림을 인쇄합니다.
실행 시점
관리자 페이지 렌더링 시 실행됩니다.
시그니처
add_action( 'admin_notices', 'my_callback' );주의할 점
모든 관리자 화면에서 실행됩니다. 모든 화면에 조건 없이 "설치해 주셔서 감사합니다!" 알림을 띄우는 플러그인은 WordPress 관리자에서 가장 미움받는 패턴입니다. 조건으로 방어하고, 닫을 수 있게 만드세요.
게시물이 생성되거나 업데이트될 때마다 실행됩니다. 메타 박스 데이터를 저장하는 일반적인 위치입니다.
실행 시점
게시물이 데이터베이스에 기록된 후에 실행됩니다.
시그니처
add_action( 'save_post', 'my_callback', 10, 3 ); // receives $post_id, $post, $update예제
add_action( 'save_post', function ( $post_id ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
if ( wp_is_post_revision( $post_id ) ) return;
if ( ! current_user_can( 'edit_post', $post_id ) ) return;
// ... now it is safe to save
}, 10, 1 );주의할 점
실제 저장뿐 아니라 자동 저장과 리비전에서도 실행됩니다. 위의 세 가지 방어가 없으면 편집기가 자동 저장할 때마다 메타 값이 빈 값으로 덮어써집니다 — 데이터가 무작위로 사라지는 것처럼 보이는 버그입니다.
게시물 편집 화면에 메타 박스를 등록합니다.
실행 시점
편집 화면이 구성될 때 실행됩니다.
시그니처
add_action( 'add_meta_boxes', 'my_callback', 10, 2 ); // receives $post_type, $post주의할 점
클래식 메타 박스는 블록 편집기가 호환 모드로 전환되지 않는 한 블록 편집기에 나타나지 않습니다. 블록 편집기 네이티브 사이트라면 대신 show_in_rest로 포스트 메타를 등록하고 사이드바 패널을 만드세요.
사용자가 성공적으로 로그인한 후에 실행됩니다.
실행 시점
인증에 성공했을 때 실행됩니다.
시그니처
add_action( 'wp_login', 'my_callback', 10, 2 ); // receives $user_login, WP_User $user새 사용자가 생성된 직후에 실행됩니다.
실행 시점
회원 가입 시 실행됩니다.
시그니처
add_action( 'user_register', 'my_callback', 10, 2 ); // receives $user_id, $userdata인증 결과를 필터링합니다. 로그인을 차단하려면 WP_Error를 반환하세요.
실행 시점
로그인 시도 중에 실행됩니다.
시그니처
add_filter( 'authenticate', 'my_callback', 30, 3 ); // receives $user, $username, $password주의할 점
여기서는 우선순위가 매우 중요합니다. WordPress 코어는 우선순위 20과 30에서 자체 검사를 연결합니다 — 너무 이르게 연결하면 비밀번호가 검사되기도 전에 실행됩니다.
REST 라우트와 필드를 등록합니다.
실행 시점
REST API가 초기화될 때 실행됩니다.
시그니처
add_action( 'rest_api_init', 'my_callback' );예제
add_action( 'rest_api_init', function () {
register_rest_route( 'myplugin/v1', '/items', array(
'methods' => 'GET',
'callback' => 'my_get_items',
'permission_callback' => '__return_true', // BE DELIBERATE ABOUT THIS
) );
} );주의할 점
permission_callback은 필수입니다 — WP 5.5부터는 이를 생략하면 알림(notice)이 발생하며, __return_true로 설정하면 엔드포인트가 완전히 공개됩니다. 진짜 공개 데이터라면 괜찮지만 그 외의 경우에는 심각한 보안 구멍입니다. 기본값에 맡기지 말고 직접 결정하세요.
wp_schedule_event()를 위한 커스텀 반복 주기를 추가합니다.
실행 시점
WordPress가 사용 가능한 스케줄 목록을 구성할 때 실행됩니다.
시그니처
add_filter( 'cron_schedules', 'my_callback' ); // receives $schedules예제
add_filter( 'cron_schedules', function ( $schedules ) {
$schedules['every_five_minutes'] = array(
'interval' => 300, // seconds
'display' => __( 'Every 5 minutes', 'textdomain' ),
);
return $schedules;
} );주의할 점
WP-Cron은 진짜 cron이 아닙니다. 누군가 사이트를 방문할 때만 실행되므로, 트래픽이 적은 사이트는 5분 스케줄을 5분마다 실행하지 못합니다. 타이밍이 정말 중요하다면 WP-Cron을 비활성화(DISABLE_WP_CRON)하고 실제 시스템 cron에서 wp-cron.php를 호출하세요.
댓글이 저장된 직후에 실행됩니다.
실행 시점
댓글 제출 시 실행됩니다.
시그니처
add_action( 'comment_post', 'my_callback', 10, 3 ); // receives $comment_id, $approved, $commentdata댓글 데이터가 저장되기 전에 필터링합니다. 스팸 검사와 유효성 검증에 사용됩니다.
실행 시점
댓글이 기록되기 전에 실행됩니다.
시그니처
add_filter( 'preprocess_comment', 'my_callback' ); // receives $commentdata주의할 점
여기서 댓글을 거부하려면 메시지와 함께 wp_die()를 호출하세요 — false를 반환해도 막히지 않습니다.
결제가 성공한 후 주문 완료(order-received) 페이지에서 실행됩니다.
실행 시점
고객이 감사(thank-you) 페이지에 도착할 때 실행됩니다.
시그니처
add_action( 'woocommerce_thankyou', 'my_callback' ); // receives $order_id주의할 점
이곳은 주문 처리를 트리거하기에 신뢰할 수 있는 위치가 아닙니다. 고객이 실제로 감사 페이지에 도달해야만 실행됩니다 — 결제 후 탭을 닫으면 절대 실행되지 않습니다. 반드시 실행되어야 하는 작업에는 woocommerce_payment_complete나 주문 상태 전환 훅을 사용하세요.
상품 페이지에서 장바구니 담기 버튼 바로 앞에 마크업을 출력합니다.
실행 시점
상품 페이지가 렌더링되는 동안 실행됩니다.
시그니처
add_action( 'woocommerce_before_add_to_cart_button', 'my_callback' );클래식 결제 페이지의 필드를 추가, 제거하거나 순서를 변경합니다.
실행 시점
결제 양식이 구성될 때 실행됩니다.
시그니처
add_filter( 'woocommerce_checkout_fields', 'my_callback' ); // receives $fields주의할 점
이것은 클래식(숏코드) 결제에만 영향을 줍니다. 더 새로운 블록 기반 결제는 이를 완전히 무시하며, JavaScript의 Slot & Fill을 통해 커스터마이징합니다. 거의 모든 사람이 처음에 여기서 걸려 넘어집니다.