Advanced Custom Fielfd(ACF) 필드 세분화 마스터 가이드
다루는 내용 전체
ACF가 기술 블로그에 필수인 이유
기술 문서에서 “Docker 버전: 24.0.7”, “최종 검증일: 2026-05-24” 같은 정보를 본문에 직접 타이핑하면 어떤 일이 생길까요? 6개월 후 정보가 바뀌었을 때 수백 개 포스트를 일일이 찾아 수정해야 하고, 특정 버전 기준의 글만 필터링하는 것은 아예 불가능합니다. ACF는 이런 메타데이터를 WordPress 데이터베이스의 완전한 규격 인덱스로 저장해 검색·필터링·자동화를 가능하게 합니다.
🆚 ACF Free vs ACF Pro 핵심 차이
| 기능 | ACF Free | ACF Pro | 실전 필요도 |
|---|---|---|---|
| 기본 필드 타입 (Text, Select 등) | ✅ | ✅ | 필수 |
| Repeater Field | ❌ | ✅ | 매우 높음 |
| Flexible Content | ❌ | ✅ | 높음 |
| Gallery Field | ❌ | ✅ | 중간 |
| Clone Field | ❌ | ✅ | 높음 |
| Options Page | ❌ | ✅ | 매우 높음 |
| ACF Blocks (Gutenberg) | ❌ | ✅ | 중간 |
| JSON Auto-sync | ✅ | ✅ | 필수 |
| REST API 지원 | ✅ | ✅ | 높음 |
| 연간 가격 | 무료 | $49~$249/년 | — |
Repeater Field와 Options Page만으로도 Pro 가격은 충분히 회수됩니다. 특히 14개 카테고리 대응 구조에서 Repeater로 다중 버전 정보를 관리하면 DB 설계 복잡도가 절반으로 줄어듭니다.
✅ 도입 전 체크리스트
- ✓ACF (Free 또는 Pro) 플러그인 설치 및 활성화 완료
- ✓Woody Snippets 플러그인 설치 완료 (PHP 스니펫 실행 환경)
- ✓사용 중인 테마 확인 (Newspaper 테마 기준으로 작성)
- !functions.php에 넣었던 기존 CSS는 완전 삭제 — Woody Snippets와 충돌하며 CSS가 이중 적용되거나 무시될 수 있음
- !Query Monitor 플러그인 설치 권장 — ACF 필드 로딩 속도 디버깅 필수 도구
글로벌 공통 필드 그룹 설계
모든 기술 포스트에 공통으로 적용되는 “마스터 필드 그룹”을 먼저 설계합니다. 이 그룹은 카테고리에 관계없이 모든 글에 노출되며, 이후 추가되는 카테고리별 그룹들의 기반 레이어가 됩니다.
📋 글로벌 공통 필드 그룹 전체 명세
| 필드 레이블 | Field Name (Slug) | 필드 타입 | 설정 세부사항 |
|---|---|---|---|
| 시리즈명 | post_series | Text | Placeholder: 예) Docker 완벽 가이드 시리즈 |
| 최종 검증일 | post_update_date | Date Picker | Return Format: Y-m-d / Display Format: Y년 m월 d일 |
| 대상 버전 | post_version | Text | Placeholder: 예) v24.0.7 / Ubuntu 24.04 LTS |
| 난이도 등급 | post_level | Select | 아래 Choices 참고. Default: medium |
| 예상 소요 시간 | post_read_time | Number | 단위: 분(min). Append: 분 읽기 |
| 테스트 환경 | post_env | Text | Placeholder: 예) Ubuntu 24.04 + Docker 26.x |
난이도 등급 (post_level) Choices 설정값
low : 🟢 초급 (Beginner) medium : 🔵 중급 (Intermediate) high : 🔴 고급 (Advanced) expert : ⚡ 전문가 (Expert)
⚙️ Location Rules 설정 (글로벌 그룹)
[공통] 기술 문서 메타 정보Post Type — is equal to — Post → 모든 포스트 유형에 자동 적용ACF Pro에서는 특정 필드 그룹을 특정 역할의 사용자에게만 보이게 제한할 수 있습니다. 에디터 권한 사용자에게는 난이도·버전 필드를 숨기고 관리자만 입력하도록 설정하면 데이터 일관성이 높아집니다.
카테고리 조건부 노출 — 모듈형 아키텍처
모든 필드를 하나의 그룹에 몰아넣으면 Docker 글을 쓰는데 AI 임베딩 모델 입력칸이 나타납니다. 카테고리 성격에 맞는 필드만 노출시키는 모듈형 분리가 핵심입니다. 빈 채로 저장되는 필드들이 wp_postmeta 테이블을 오염시키는 것도 막을 수 있습니다.
📦 3개 전문 필드 그룹 분리 설계
| 그룹명 | Field Slug | 타입 | 트리거 카테고리 (OR 연결) |
|---|---|---|---|
| [기술] AI & 자동화 | ai_engine | Text | Automation, Local AI, Media Gen, n8n |
| [기술] 컨테이너 & 시스템 | deployment_type | Radio Button | Docker, NAS, VM, DevOps, Server |
base_os | Text | ||
| [기술] 데이터 & 인프라 | target_system | Text | Data Eng, Data Ops, Security, Database |
data_tool | Text |
deployment_type Radio Button Choices
docker : 🐳 Docker Compose baremetal : 🖥️ Bare Metal synology : 💾 Synology Package vm : 💻 Virtual Machine kubernetes : ☸️ Kubernetes
Location Rules에서 세로로 추가(Add rule group)하면 AND 조건입니다. Docker AND Local AI를 동시에 만족해야 하므로 실질적으로 절대 트리거되지 않습니다. 반드시 우측 “or” 버튼으로 가로 추가해야 OR 조건(하나만 해당해도 노출)이 됩니다.
올바른 Location Rules 설정 순서 (OR 병렬)
Post Category — is equal to — DockerPost Category — is equal to — NASPost Category — is equal to — VM … 필요한 카테고리 수만큼 반복Woody Snippets PHP 구현 + CSS 완전 적용
🔴 CSS가 안 먹히는 정확한 원인
Woody Snippets의 PHP 스니펫이 dp-meta-card, dp-meta-badge 같은 클래스명을 HTML로 출력해도 실제 화면에 스타일이 적용되지 않는 이유는 다음 3가지 중 하나입니다.
| 원인 | 증상 | 해결 방법 |
|---|---|---|
| CSS가 Theme CSS에만 있고 Snippets 출력 시점엔 미로드 | 클래스 있는데 스타일 없음 | 인라인 스타일로 완전 독립화 |
| 캐시 플러그인이 PHP 출력을 정적으로 캐싱 | 처음엔 되다가 안 됨 | 해당 단축코드 캐시 제외 설정 |
| Newspaper 테마 빌더가 Shortcode를 Escape 처리 | HTML 태그가 텍스트로 출력 | Cloud Template 숏코드 블록 사용 |
| functions.php와 Woody 동시 선언으로 충돌 | 숏코드가 아예 동작 안 함 | functions.php 쪽 완전 삭제 |
외부 CSS 파일에 의존하지 않고, PHP 스니펫이 <style> 블록과 HTML을 함께 출력하면 어떤 환경에서도 100% 동작합니다. 아래 완성 코드가 바로 이 방식입니다.
실제 출력 미리보기
🐍 Woody Snippets 최종 완성 코드 (CSS 인라인 완전 독립형)
function agibop_render_tech_meta_card() {
$id = get_the_ID();
if ( ! $id ) return '';
/* ── ACF 필드 수집 ─────────────────────────── */
$series = get_field('post_series', $id);
$updated = get_field('post_update_date', $id);
$version = get_field('post_version', $id);
$level = get_field('post_level', $id);
$read_time = get_field('post_read_time', $id);
$env = get_field('post_env', $id);
$ai_engine = get_field('ai_engine', $id);
$deploy_type = get_field('deployment_type', $id);
$base_os = get_field('base_os', $id);
$target_sys = get_field('target_system', $id);
$data_tool = get_field('data_tool', $id);
/* ── 값이 하나도 없으면 출력하지 않음 ────── */
$has_data = $series || $updated || $version || $level || $read_time
|| $env || $ai_engine || $deploy_type || $base_os
|| $target_sys || $data_tool;
if ( ! $has_data ) return '';
/* ── 배포 방식 라벨 변환 ─────────────────── */
$deploy_labels = [
'docker' => '🐳 Docker Compose',
'baremetal' => '🖥️ Bare Metal',
'synology' => '💾 Synology Package',
'vm' => '💻 Virtual Machine',
'kubernetes' => '☸️ Kubernetes',
];
$deploy_label = $deploy_labels[ $deploy_type ] ?? $deploy_type;
/* ── 난이도 배지 색상 ────────────────────── */
$level_map = [
'low' => ['label' => '🟢 초급', 'color' => '#4ade80', 'bg' => 'rgba(34,197,94,.15)', 'border' => 'rgba(34,197,94,.3)'],
'medium' => ['label' => '🔵 중급', 'color' => '#60a5fa', 'bg' => 'rgba(96,165,250,.15)', 'border' => 'rgba(96,165,250,.3)'],
'high' => ['label' => '🔴 고급', 'color' => '#f87171', 'bg' => 'rgba(248,113,113,.15)', 'border' => 'rgba(248,113,113,.3)'],
'expert' => ['label' => '⚡ 전문가', 'color' => '#fbbf24', 'bg' => 'rgba(251,191,36,.15)', 'border' => 'rgba(251,191,36,.3)'],
];
$lv = $level_map[ $level ] ?? null;
/* ── CSS (인라인 — 외부 의존 없음) ──────── */
$css = '
';
/* ── HTML 조립 ───────────────────────────── */
$html = $css . '';
return $html;
}
add_shortcode( 'agibop_meta', 'agibop_render_tech_meta_card' );⚙️ Woody Snippets 설정 방법
agibop 기술 메타 카드 / 타입: PHP Snippet[agibop_meta] 입력 → 저장- 캐시 플러그인 전체 Purge — WP Rocket, W3 Total Cache, LiteSpeed Cache 등 모두 캐시 비우기 후 확인
- functions.php에 동일 숏코드 선언 존재 여부 — 중복 선언 시 Woody 코드가 무시됩니다. functions.php에서
add_shortcode('agibop_meta', ...)완전 삭제 - Newspaper 테마 빌더가 Shortcode를 Raw Text로 처리 — Cloud Template의 Shortcode 전용 블록(숏코드 위젯)을 사용했는지 확인. 일반 텍스트 블록에 넣으면 HTML이 이스케이프됨
- ACF 필드 Slug 오타 —
get_field('post_series')의 슬러그가 ACF 설정의 Field Name과 완전히 일치해야 합니다. ACF → Field Groups → 필드 편집 → Field Name 값 직접 확인
고급 필드 타입 완전 정복 (ACF Pro)
기본 Text·Select 필드를 넘어 ACF Pro의 고급 필드 타입을 활용하면 기술 블로그를 진정한 지식 관리 시스템으로 업그레이드할 수 있습니다.
🔁 Repeater Field — 다중 값 반복 입력
하나의 포스트에 여러 버전 정보, 여러 명령어, 여러 참고 링크를 구조적으로 관리할 때 사용합니다. Docker 가이드에서 “지원 버전 목록”을 반복 추가하는 용도로 최적입니다.
// ACF 설정: Field Name = version_history (Repeater) // Sub-fields: ver_num (Text), ver_date (Date), ver_status (Select) if ( have_rows('version_history') ) : echo '<ul class="version-list">'; while ( the_row() ) : $num = get_sub_field('ver_num'); $date = get_sub_field('ver_date'); $status = get_sub_field('ver_status'); // stable / beta / deprecated echo '<li>' . esc_html($num) . ' (' . esc_html($date) . ') - ' . esc_html($status) . '</li>'; endwhile; echo '</ul>'; endif;
🎨 Flexible Content — 드래그 앤 드롭 레이아웃 빌더
블로그 본문 내에 “코드 블록 레이아웃”, “주의사항 카드”, “비교표 레이아웃” 등 다양한 콘텐츠 블록을 순서대로 조합해 넣을 때 사용합니다. Gutenberg보다 훨씬 구조적인 데이터 관리가 가능합니다.
⚙️ Options Page — 사이트 전역 설정 관리
특정 포스트가 아닌 사이트 전체에 적용되는 글로벌 설정을 ACF로 관리합니다. 예를 들어 “기본 테스트 환경”, “공통 면책 조항 텍스트”, “시리즈 목록”을 Options Page에 저장하면 모든 글에서 get_field('옵션명', 'option')으로 불러올 수 있습니다.
// functions.php 또는 Woody Snippet에 추가 if ( function_exists('acf_add_options_page') ) { acf_add_options_page([ 'page_title' => '블로그 전역 설정', 'menu_title' => 'Site Options', 'menu_slug' => 'site-options', 'capability' => 'manage_options', 'redirect' => false, ]); } // 조회 시 두 번째 인자로 'option' 전달 $disclaimer = get_field('global_disclaimer', 'option'); $site_env = get_field('default_test_env', 'option');
🔗 Relationship & Post Object — 글 간 연계
기술 시리즈 글들을 서로 연결하거나, “관련 포스트” 필드를 ACF로 관리할 때 사용합니다. Relationship 필드는 다중 선택, Post Object는 단일 선택입니다. WP_Query 없이 구조화된 방식으로 연관 포스트를 출력할 수 있어 SEO 내부 링크 구조 강화에 매우 효과적입니다.
📋 Clone Field — 필드 그룹 재사용
여러 카테고리 그룹에서 공통으로 쓰이는 필드(예: “참고 URL”, “관련 공식 문서”)를 Clone Field로 한 번만 정의하고 여러 그룹에서 재사용합니다. 필드 수정 시 원본 하나만 고치면 모든 Clone이 자동 갱신됩니다.
시리즈 연결: Relationship(related_series)
전역: Options Page(disclaimer, default_env)
다중 버전: Repeater(version_history)
ACF JSON Sync & 버전 관리
ACF는 필드 그룹을 JSON 파일로 자동 저장하는 기능을 내장하고 있습니다. 이를 활용하면 필드 구조를 Git으로 버전 관리하고, 스테이징 서버와 프로덕션 서버 간 동기화를 자동화할 수 있습니다.
🔧 JSON Auto-sync 활성화
// child-theme/functions.php 또는 Woody Snippet에 추가 // ACF JSON 파일을 테마 폴더 내 acf-json/ 에 저장 add_filter('acf/settings/save_json', function() { return get_stylesheet_directory() . '/acf-json'; }); add_filter('acf/settings/load_json', function($paths) { $paths[] = get_stylesheet_directory() . '/acf-json'; return $paths; });
/acf-json/ 폴더를 생성합니다. 폴더 권한은 755.group_xxxx.json 파일이 생성됩니다.git add acf-json/*.json → 필드 구조 변경사항이 버전 관리됩니다. 팀원이 pull 후 자동 동기화.acf-json 파일을 Git을 통해 프로덕션에 배포하면, DB에 필드 그룹을 수동으로 재생성할 필요가 없습니다. WordPress가 json 파일을 감지해 자동으로 동기화합니다. Sync Available 버튼이 나타나면 클릭해서 DB에 반영합니다.
성능 최적화 & 디버깅 매뉴얼
⚡ DB 쿼리 최적화
// 개별 get_field() 대신 get_fields()로 한 번에 로드 // 쿼리 수: 6회 → 1회로 감소 $all_fields = get_fields( get_the_ID() ); $series = $all_fields['post_series'] ?? ''; $version = $all_fields['post_version'] ?? ''; $level = $all_fields['post_level'] ?? ''; $deploy = $all_fields['deployment_type'] ?? ''; // 추가: Transient 캐싱으로 반복 조회 방지 function agibop_get_meta_cached( $post_id ) { $key = 'agibop_meta_' . $post_id; $data = get_transient( $key ); if ( false === $data ) { $data = get_fields( $post_id ) ?: []; set_transient( $key, $data, HOUR_IN_SECONDS ); } return $data; }
🔍 데이터 누락 디버깅 체크포인트
| 증상 | 원인 | 확인 방법 | 해결 |
|---|---|---|---|
| 필드 선택했는데 출력 안 됨 | Field Name(Slug) 불일치 | ACF → 필드 편집 → Field Name 직접 확인 | 코드의 슬러그와 정확히 일치시킴 |
| 숏코드가 텍스트로 출력 | 빌더에서 이스케이프 처리 | Shortcode 전용 블록 사용 여부 확인 | Cloud Template의 Shortcode 위젯 사용 |
| 수정해도 반영 안 됨 | 캐시 오염 | 캐시 플러그인 확인 | 캐시 전체 Purge |
| 숏코드 자체가 동작 안 함 | functions.php 중복 선언 | functions.php에서 동일 add_shortcode 검색 | functions.php쪽 완전 삭제 |
| PHP Fatal Error | Woody가 테마보다 먼저 로드 | 에러 로그 확인 | Woody 우선순위 20 이상으로 설정 |
🚨 대표적인 에러 메시지와 해결
→ Woody Snippets가 ACF보다 먼저 실행됨. Woody 설정에서 Priority를 20으로 낮추거나 add_action hook을 ‘after_setup_theme’으로 변경
→ 필드 그룹이 현재 포스트 타입에 적용되지 않음. Location Rules 재확인
🗃️ 오브젝트 캐시 & Redis 운영 주의
// ACF 필드 저장 시 해당 포스트의 캐시 자동 삭제 add_action('acf/save_post', function( $post_id ) { delete_transient( 'agibop_meta_' . $post_id ); // Redis 사용 시 if ( function_exists('wp_cache_delete') ) { wp_cache_delete( 'agibop_meta_' . $post_id, 'acf_cache' ); } }, 20);
추천 확장 기능 & REST API 연동
🌐 ACF 데이터 REST API 노출
ACF Pro는 기본으로 ACF 필드를 WordPress REST API에 포함시킵니다. Free 버전이라면 ACF to REST API 플러그인을 설치하세요. 이를 활용하면 n8n, 외부 스크립트, 모바일 앱 등에서 포스트 메타 데이터를 JSON으로 받아볼 수 있습니다.
# 포스트 ID 123의 ACF 필드 전체 조회 curl https://your-blog.com/wp-json/wp/v2/posts/123?_fields=id,title,acf # 응답 예시 { "id": 123, "title": { "rendered": "Docker 완벽 가이드" }, "acf": { "post_series": "Docker 마스터 시리즈", "post_version": "v26.1.4", "post_level": "medium", "deployment_type": "docker" } }
🤖 n8n으로 자동 포스팅 시 ACF 메타 함께 등록
Method: POST
URL: https://your-blog.com/wp-json/wp/v2/posts
Headers:
Authorization: Basic [base64(user:app_password)]
Content-Type: application/json
Body:
{
"title": "Docker Swarm 완전 정복",
"content": "본문 내용...",
"status": "publish",
"categories": [15],
"acf": {
"post_series": "Docker 마스터 시리즈",
"post_version": "v26.1.4",
"post_update_date": "2026-05-24",
"post_level": "high",
"deployment_type": "docker",
"post_env": "Ubuntu 24.04 + Docker 26.x"
}
}📦 추천 보완 플러그인
✅ 전체 구축 완료 체크리스트
- ✓글로벌 공통 필드 그룹 생성 및 모든 포스트에 Location Rules 적용
- ✓카테고리별 3개 전문 그룹 생성 및 OR 조건 Location Rules 설정
- ✓Woody Snippets PHP 코드 등록 및 숏코드
[agibop_meta]동작 확인 - ✓Newspaper Cloud Template에 Shortcode 블록 배치 완료
- ✓실제 포스트에서 메타 카드 정상 출력 확인
- ✓acf-json 폴더 설정 및 Git 버전 관리 시작
- ✓functions.php 기존 CSS 및 중복 숏코드 완전 삭제
- !캐시 플러그인 Purge 후 최종 동작 검증
- !Query Monitor로 ACF 쿼리 수 모니터링 (포스트당 10회 이하 권장)
🎯 한 줄 요약: ACF + Woody Snippets 조합에서 CSS가 안 먹히는 건 외부 의존 때문입니다. PHP 스니펫 안에 <style>을 직접 출력하는 인라인 독립형으로 구현하면 캐시, 테마, 플러그인 충돌과 무관하게 100% 동작합니다.
