[워드프레스] 20. CPT : 커스텀 포스트 타입 만드는 법

워드프레스 해부 20편 - 커스텀 포스트 타입 만드는 법

작성자

카테고리:

* 이 게시물은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

(워드프레스 해부 ⑳) CPT

워드프레스 기본은 “글”과 “페이지”뿐이다. 그런데 “책”, “포트폴리오”, “이벤트”처럼 나만의 콘텐츠 종류가 필요할 때가 있다. 이때 만드는 게 커스텀 포스트 타입(CPT)이다.

놀라운 건, 새 콘텐츠 종류를 만들어도 DB 테이블은 새로 안 생긴다는 점이다. 8편에서 봤듯 전부 wp_posts에 post_type='book'으로 들어간다. 등록은 register_post_type()을 init 훅에 걸어서 한다.

직접 해보기

add_action( 'init', function() {
    register_post_type( 'book', array(
        'labels'      => array( 'name' => '책', 'singular_name' => '책' ),
        'public'      => true,
        'has_archive' => true,
        'menu_icon'   => 'dashicons-book',
        'supports'    => array( 'title', 'editor', 'thumbnail' ),
        'show_in_rest'=> true,   // 블록 편집기·REST 지원
    ) );
} );

show_in_rest => true가 중요하다. 이게 있어야 블록 편집기로 편집되고 REST API에도 노출된다. 없으면 옛날 편집기로 뜬다.

✅ 확인 — 등록 후 관리자 메뉴에 “책”이 생기고, wp post-type list에 book이 나오면 성공. 책을 하나 저장한 뒤 wp_posts에서 post_type='book' 행을 확인하면, 새 종류도 결국 같은 테이블에 산다는 게 보인다.

실무에서 쓰는 등록 한 벌

개념만 보면 register_post_type('book', ...) 한 줄이지만, 실제로 쓸 만하게 만들려면 아카이브·블록 에디터·REST까지 챙긴 한 벌을 쓴다. 아래가 내가 새 CPT를 만들 때 복사해서 시작하는 뼈대다.

add_action( 'init', function () {
    register_post_type( 'book', array(
        'labels'       => array( 'name' => '책', 'singular_name' => '책' ),
        'public'       => true,
        'has_archive'  => true,          // /book/ 목록 페이지 생성
        'show_in_rest' => true,          // 블록 에디터·REST 노출 (사실상 필수)
        'menu_icon'    => 'dashicons-book',
        'supports'     => array( 'title', 'editor', 'thumbnail', 'excerpt' ),
        'rewrite'      => array( 'slug' => 'books' ),
    ) );
} );

supports 배열이 편집 화면에 뭘 띄울지를 정한다. editor가 빠지면 본문 편집기가 아예 안 나오고, thumbnail이 있어야 대표 이미지 칸이 생긴다. 필요 없는 건 빼서 편집 화면을 깔끔하게 유지한다.

show_in_rest를 빠뜨리면 벌어지는 일

이 값 하나가 은근히 사람을 잡는다. 블록 에디터는 화면 뒤에서 REST API로 데이터를 읽고 쓴다. 그래서 show_in_rest가 false면 이 CPT 편집 화면이 옛날 클래식 에디터로 떨어지거나, 쿼리 루프 블록이 이 타입을 목록에서 못 찾는다. 헤드리스로 프런트를 따로 만든다면 아예 데이터를 못 가져온다. 요즘은 true가 기본값이나 다름없다.

아카이브와 단일 페이지에 전용 디자인 주기

has_archive => true를 켜면 /books/ 주소로 이 타입 글이 모인 목록 페이지가 생긴다. 여기에 전용 디자인을 주고 싶으면 템플릿 계층을 따라 파일을 만들면 된다. 클래식 테마는 목록에 archive-book.php, 개별 글에 single-book.php, 블록 테마는 archive-book.html·single-book.html이다. 없으면 일반 archive·single로 자연스럽게 폴백한다.

퍼머링크 flush, 언제 진짜 필요한가

CPT가 목록에 안 보이거나 주소가 404면 습관적으로 설정 → 고유주소를 저장해 flush한다. 그런데 flush가 실제로 필요한 건 rewrite 슬러그나 has_archive를 바꿨을 때뿐이다. 라벨이나 supports 같은 걸 손볼 땐 flush가 필요 없다. 반대로 코드 안에서 매 요청마다 flush_rewrite_rules()를 호출하는 실수는 페이지 성능을 갉아먹으니 절대 넣지 말자 — flush는 플러그인 활성화 같은 특별한 순간에 한 번이면 충분하다.

분류를 붙여야 진짜 콘텐츠 타입이 된다

책 CPT를 만들었으면 다음은 분류다. 커스텀 택소노미로 ‘장르’를 만들어 연결하면, 글(책)과 분류(장르)가 짝을 이뤄 필터·아카이브가 돌아간다. CPT 하나만으론 반쪽이고, 여기에 택소노미가 붙어야 관리할 만한 콘텐츠 구조가 완성된다.

실제로 써먹는 예 — 이벤트 타입

‘책’은 설명용이고, 현장에서 자주 만드는 CPT는 이벤트·후기·채용공고·FAQ 같은 것들이다. 예를 들어 이벤트라면 supports에 title·editor·thumbnail을 두고, 시작일 같은 부가 정보는 타입이 아니라 커스텀 필드로 붙인다. 그런 다음 WP_Query에서 그 날짜 메타로 정렬하면 ‘다가오는 이벤트’ 목록이 완성된다.

포인트는 역할 분담이다. CPT는 ‘무엇의 종류인가’(이벤트냐 후기냐)를, 커스텀 필드는 ‘그 하나에 딸린 값’(날짜·장소·평점)을, 택소노미는 ‘어떻게 묶을까’(카테고리·태그)를 맡는다. 이 셋을 구분해서 쓰면 어떤 콘텐츠 구조든 깔끔하게 모델링된다.

콘텐츠 종류를 만들었으니, 다음 편은 그걸 분류할 나만의 택소노미(분류 체계)다.

자주 묻는 질문 (FAQ)

커스텀 포스트 타입은 왜 만드나요?

글·페이지와 다른 종류의 콘텐츠(제품·포트폴리오 등)를 별도로 관리하려고요. register_post_type으로 만듭니다.

CPT가 목록에 안 보여요.

퍼머링크를 한 번 저장(flush)하거나, register 시 rewrite·has_archive 설정을 확인하세요.

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다