블로그

WordPress 훅 아키텍처: 액션 vs 필터 설명

모든 훌륭한 플러그인의 기반입니다. PAGEnza AI가 유지 관리 가능하고 확장 가능한 코드를 만드는 데 훅과 필터를 사용하는 방법을 알아보세요.

모든 WordPress 플러그인은 두 가지 중 하나를 수행합니다. 특정 순간에 코드를 실행하거나(액션), 사용되기 전에 값을 수정합니다(필터). 그것이 전부입니다. 전체 WordPress 플러그인 생태계는 이 구분에 기반하여 구축되었습니다.

이 둘의 차이점과 언제 사용해야 하는지를 이해하는 것이 작동하는 플러그인과 문제를 일으키는 플러그인을 구분하는 기준입니다.

액션: 특정 시점에 무언가를 실행

액션 훅은 WordPress(또는 다른 플러그인)가 특정 순간에 보내는 신호입니다. 이 신호에 함수를 연결하면 신호가 발생할 때 함수가 실행됩니다.

add_action( 'wp_enqueue_scripts', 'my_plugin_load_assets' );

function my_plugin_load_assets() {
    wp_enqueue_style( 'my-plugin', plugin_dir_url( __FILE__ ) . 'style.css' );
    wp_enqueue_script( 'my-plugin', plugin_dir_url( __FILE__ ) . 'script.js', ['jquery'], '1.0', true );
}

wp_enqueue_scripts는 WordPress가 프런트엔드에 대한 에셋을 로드할 준비를 할 때 실행됩니다. 이를 훅하는 것은 템플릿에 직접 <script> 태그를 삽입하는 것이 아니라 CSS와 JS를 로드하는 올바른 방법입니다.

계속해서 사용하게 될 일반적인 액션 훅:

  • init — 일찍 실행되며, 포스트 타입 및 택소노미 등록에 좋습니다.
  • wp_enqueue_scripts — 프런트엔드 에셋 로드
  • admin_enqueue_scripts — 관리자 에셋 로드
  • save_post — 포스트가 저장될 때 실행되며, 사용자 정의 필드 처리에 좋습니다.
  • wp_ajax_{action} — 인증된 사용자의 AJAX 요청 처리
  • wp_ajax_nopriv_{action} — 로그인하지 않은 사용자의 AJAX 처리

필터: 사용되기 전에 값을 수정

필터 훅은 값을 제공하고, 수정할 수 있게 하며, 수정된 버전을 반환하도록 합니다. 그러면 WordPress는 원본 대신 수정된 값을 사용합니다.

add_filter( 'the_content', 'my_plugin_append_cta' );

function my_plugin_append_cta( $content ) {
    if ( ! is_single() ) {
        return $content;
    }
    $cta = '<div class="post-cta">PAGEnza를 사용해 볼 준비가 되셨나요? <a href="#">무료로 시작하기 →</a></div>';
    return $content . $cta;
}

가장 중요한 규칙: 필터에서는 항상 무언가를 반환해야 합니다. return을 잊으면 값이 null이 되어 해당 값을 사용하던 모든 것이 깨지게 됩니다.

일반적인 필터 훅:

  • the_content — 표시 전의 포스트 내용
  • the_title — 포스트 제목
  • wp_nav_menu_items — 네비게이션 메뉴 HTML
  • upload_mimes — 허용된 파일 업로드 유형
  • plugin_action_links_{plugin-file} — 플러그인 목록 페이지에 표시되는 링크

PAGEnza AI는 훅을 어떻게 사용하는가

플러그인 빌더가 플러그인을 생성할 때, 생성자는 생성자 내에서 훅에 연결된 메서드를 가진 클래스를 중심으로 코드를 구성합니다. 이 패턴은 전역 함수 이름 충돌을 피하고 코드를 체계적으로 유지합니다.

class My_Plugin {
    public function __construct() {
        add_action( 'init', [ $this, 'register_post_type' ] );
        add_action( 'wp_enqueue_scripts', [ $this, 'load_assets' ] );
        add_filter( 'the_content', [ $this, 'append_content' ] );
    }

    public function register_post_type() { /* ... */ }
    public function load_assets() { /* ... */ }
    public function append_content( $content ) {
        // 항상 반환해야 함
        return $content;
    }
}

new My_Plugin();

보안 스캔은 AJAX 핸들러가 어떤 작업을 수행하기 전에 논스(nonce) 확인과 권한 확인을 모두 포함하는지 구체적으로 확인합니다.

add_action( 'wp_ajax_my_action', [ $this, 'handle_ajax' ] );

public function handle_ajax() {
    // 보안: 논스 확인
    check_ajax_referer( 'my_nonce_action', 'nonce' );

    // 보안: 권한 확인
    if ( ! current_user_can( 'manage_options' ) ) {
        wp_send_json_error( '권한 부족', 403 );
    }

    // 이제 안전하게 처리할 수 있습니다.
    $data = sanitize_text_field( $_POST['data'] ?? '' );
    wp_send_json_success( [ 'result' => $data ] );
}

이 둘 중 하나라도 누락되면 보안 문제로 플래그가 지정되어 플러그인 출시가 차단됩니다.

우선순위와 훅 큐

여러 함수가 동일한 훅에 연결되어 있을 때, 우선순위에 따라 실행됩니다(낮은 숫자 = 먼저 실행). 기본 우선순위는 10입니다.

add_action( 'init', 'runs_first', 5 );
add_action( 'init', 'runs_second', 10 );   // 기본값
add_action( 'init', 'runs_last', 20 );

플러그인이 다른 플러그인의 코드보다 먼저 또는 후에 실행되어야 할 때 중요합니다. 다른 플러그인도 수정하는 것을 수정하는 경우, 우선순위가 누가 이길지를 결정합니다.

일반적인 패턴: 테마의 필터를 재정의하는 경우, 테마의 코드 이후에 실행되도록 우선순위 20 이상을 사용합니다.

훅 제거

다른 사람이 추가한 훅(테마 및 플러그인 훅 포함)을 제거할 수 있습니다.

remove_action( 'wp_head', 'wp_generator' );  // <head>에서 WP 버전 제거
remove_filter( 'the_content', 'wpautop' );   // 자동 단락 줄 바꿈 제거

주의사항: 원본 add_action/add_filter가 실행된 후에 remove_action/remove_filter를 호출해야만 훅을 제거할 수 있습니다. 일반적으로 제거를 더 늦은 액션에 훅하는 것을 의미합니다.