theme.json 완전 정리: settings와 styles, 그리고 병합 순서
theme.json에서 settings와 styles가 서로 다른 일을 하는 이유를 이해하고, 워드프레스의 병합 순서를 따라가며 아무것도 반영되지 않는 블록 테마 수정을 해결하세요.
게시됨
theme.json은 블록 테마 루트에 놓이는 하나의 설정 파일이며, 서로 다른 두 가지 일을 합니다. settings는 블록 편집기가 사용자에게 무엇을 제공할지 정하고, styles는 사이트가 기본적으로 어떻게 보일지를 정합니다. 워드프레스는 이 파일을 파싱해 자체 기본값 및 사이트 편집기에 저장된 내용과 병합한 뒤, 그 결과를 CSS 사용자 정의 속성과 인라인 스타일시트 형태로 모든 페이지에 출력합니다.
theme.json 수정이 아무 효과도 없어 보이는 이유는 대부분 이 둘을 혼동해서입니다. settings에 색상을 선언한다고 그 색상이 어디엔가 적용되지는 않습니다. 변수 하나와 편집기 사이드바의 색상 견본이 생길 뿐입니다.
최상위 키
가장 단순한 파일은 이런 모습입니다.
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {},
"styles": {},
"templateParts": [],
"customTemplates": []
}
| 키 | 하는 일 |
|---|---|
$schema | 코드 편집기의 자동완성과 검증용일 뿐입니다. 워드프레스는 무시합니다. |
version | 어떤 스키마 형태로 파싱할지 알려줍니다. 테마 버전이 아닙니다. |
settings | CSS 변수를 생성하고 편집기가 노출할 항목을 정합니다. |
styles | 실제 기본 스타일을 적용합니다. |
templateParts | parts/에 있는 파트와 그것이 속한 영역을 선언합니다. |
customTemplates | templates/의 페이지 템플릿을 글 편집기에 등록합니다. |
version이 헷갈리는 이유는 테마 버전 번호처럼 보이기 때문입니다. 그렇지 않습니다. 이 값은 파싱 방식을 선택하며, 오래된 워드프레스는 자신이 모르는 스키마의 키를 조용히 무시합니다. 구버전 설치를 지원한다면 새 키가 알아서 잘 처리될 거라 가정하지 말고 그 설치가 이해하는 버전을 목표로 하세요. 이 글을 쓰는 시점에서는 버전 3이 최신이며, 버전 2도 여전히 널리 쓰이고 정상적으로 파싱됩니다.
$schema는 워드프레스가 호스팅하는 스키마 URL을 가리킵니다. trunk로 고정하면 코드 편집기에서 최신 힌트를 받을 수 있고, 의도적으로 구버전 스키마에 머무른다면 버전이 명시된 URL이 더 안전합니다.
settings: 편집기가 제공하는 것
settings 아래의 모든 항목은 CSS 사용자 정의 속성을 만들고, 대부분의 경우 편집기 컨트롤도 함께 만듭니다. 하지만 settings 아래 어떤 것도 스타일을 적용하지는 않습니다.
{
"settings": {
"color": {
"palette": [
{ "slug": "brand", "color": "#1f4ed8", "name": "Brand" },
{ "slug": "ink", "color": "#111827", "name": "Ink" }
],
"custom": false
},
"typography": {
"fontSizes": [
{ "slug": "small", "size": "0.875rem", "name": "Small" },
{ "slug": "large", "size": "1.5rem", "name": "Large" }
]
},
"layout": {
"contentSize": "680px",
"wideSize": "1200px"
}
}
}
이 설정은 프리셋 경로와 slug를 조합한 이름의 변수를 만들어냅니다.
--wp--preset--color--brand
--wp--preset--color--ink
--wp--preset--font-size--small
--wp--preset--font-size--large
또한 .has-brand-color, .has-brand-background-color 같은 유틸리티 클래스도 함께 생성되는데, 편집기는 이 클래스로 사용자가 고른 색상 견본을 블록에 적용합니다.
"custom": false 한 줄은 settings의 나머지 절반, 즉 옵션을 꺼버리는 쪽입니다. 이 값을 주면 임의 색상 선택기가 사라지고 사용자에게는 여러분이 정한 팔레트만 남습니다. 같은 방식이 전반에 걸쳐 통합니다. settings.typography.customFontSize, settings.spacing.customSpacingSize, settings.border 등이 그렇습니다. settings 아래에는 장식용 키가 하나도 없습니다. 각 키는 변수를 추가하거나, 컨트롤을 추가하거나, 컨트롤을 없앱니다.
settings.custom은 직접 만든 변수를 담는 자유 영역입니다.
{
"settings": {
"custom": {
"lineHeight": { "body": 1.6 },
"shadow": { "card": "0 1px 3px rgba(0,0,0,0.12)" }
}
}
}
이 값들은 --wp--custom--line-height--body와 --wp--custom--shadow--card가 됩니다. 변환 규칙을 눈여겨보세요. 카멜 표기 키는 하이픈으로 분리되고, 중첩 구조는 이중 하이픈으로 이어집니다. 변수 이름을 잘못 적는 것이 값이 조용히 기본값으로 되돌아가는 흔한 원인입니다.
설정은 블록별로 범위를 좁힐 수도 있습니다. 버튼에는 색상 선택기를 허용하고 문단에는 허용하지 않는 식입니다.
{
"settings": {
"blocks": {
"core/paragraph": {
"color": { "custom": false, "customGradient": false }
}
}
}
}
styles: 실제로 렌더링되는 것
값이 실제로 적용되는 곳은 styles입니다. 구조는 편집기와 같습니다. 루트 레벨이 있고, 그다음 elements, 그다음 blocks입니다.
{
"styles": {
"color": {
"background": "var(--wp--preset--color--base)",
"text": "var(--wp--preset--color--ink)"
},
"typography": {
"lineHeight": "var(--wp--custom--line-height--body)"
},
"elements": {
"link": {
"color": { "text": "var(--wp--preset--color--brand)" },
":hover": { "typography": { "textDecoration": "none" } }
}
},
"blocks": {
"core/quote": {
"typography": { "fontStyle": "italic" },
"spacing": { "padding": { "left": "var(--wp--preset--spacing--40)" } }
}
}
}
}
루트 레벨의 styles는 body에 적용됩니다. elements는 블록이 아닌 HTML 기본 요소, 즉 링크와 버튼, 제목, 캡션을 다룹니다. blocks는 이름으로 특정 블록 타입을 지정합니다.
솔직한 한계도 있습니다. styles는 CSS가 표현할 수 있는 모든 것을 담지 못합니다. 미디어 쿼리를 직접 작성할 수 없고, 복잡한 선택자와 애니메이션도 없으며, 지원되는 가상 클래스 상태도 몇 가지뿐입니다. 유동형 타이포그래피와 레이아웃 기반 크기 지정이 브레이크포인트로 하던 일의 상당 부분을 대신하지만, 전부는 아닙니다. 실제 배포되는 블록 테마 대부분은 theme.json과 함께 적당한 크기의 스타일시트를 두고 있으며, 이는 실패가 아니라 정상적인 결과입니다.
settings와 styles를 혼동하는 함정
가장 자주 들어오는 질문은 결국 “브랜드 색상을 추가했는데 아무것도 안 바뀌어요”의 변형입니다.
맞습니다. settings.color.palette에 추가한 것은 --wp--preset--color--brand 변수와 색상 견본을 만들었을 뿐, 아무것도 적용하지 않았습니다. 그 색을 기본 링크 색으로 만들려면 styles에도 적어야 합니다.
{
"settings": {
"color": {
"palette": [{ "slug": "brand", "color": "#1f4ed8", "name": "Brand" }]
}
},
"styles": {
"elements": {
"link": { "color": { "text": "var(--wp--preset--color--brand)" } }
}
}
}
이렇게 이해하면 편합니다. settings는 사용자에게 건네는 물감 상자이고, styles는 사용자가 오기 전에 여러분이 미리 칠해 두는 밑칠입니다.
병합 순서, 낮은 것부터 높은 것까지
테마 파일을 “무시하는” 사이트의 정체가 여기서 드러납니다. 워드프레스는 CSS를 내보내기 전에 여러 층을 병합합니다.
- 워드프레스 코어 기본값 — 코어 자체가 기본 팔레트와 글꼴 크기, 여백 스케일을 담은
theme.json을 함께 배포합니다. - 부모 테마의
theme.json - 자식 테마의
theme.json— 파일 전체를 갈아치우는 것이 아니라 부모 위에 키 단위로 병합됩니다. - 데이터베이스에 저장된 전역 스타일 — 사이트 편집기의 스타일 패널이 기록하는 값입니다.
- 개별 블록에 지정된 스타일 — 글 내용에 저장된 속성으로, 인라인 스타일이나 클래스로 렌더링됩니다.
사이트를 망가뜨리는 것은 4번 층입니다. 누군가 스타일 패널을 열고 저장하는 순간 워드프레스는 전역 스타일 기록을 저장하며, 그 기록이 담고 있는 모든 속성에서 여러분의 파일보다 우선합니다. 그 뒤로는 theme.json을 고쳐도 해당 속성은 눈에 띄는 변화가 없습니다. 디스크의 파일은 분명히 달라졌는데 배포 후에도 사이트가 똑같아 보이는 상황이 그것입니다.
해결책은 !important로 밀어붙이는 것이 아니라 저장된 기록을 지우는 것입니다. 사이트 편집기를 열고 스타일로 이동한 뒤 리비전 패널에서 테마 기본값으로 되돌리세요. 다만 먼저 클라이언트나 사이트 소유자에게 확인을 받으세요. 되돌리기는 그들의 커스터마이징을 버리는 일이며, 이는 공짜 작업이 아니라 실제 비용입니다.
두 번째로 의심할 것은 캐시입니다. 워드프레스는 요청마다 파일을 다시 읽지 않고 파싱된 theme.json 데이터를 캐시합니다. 운영 환경에서는 바라던 동작이지만, 개발 중에는 정확히 원치 않는 동작입니다. WP_DEBUG를 켜거나, 최신 버전이라면 테마 개발 모드 설정을 켜면 워드프레스가 매번 파일을 다시 읽습니다. 배포나 캐시 비우기 이후에야 수정이 반영된다면 바로 이 현상입니다.
templateParts와 customTemplates
둘 다 이미 테마 안에 존재하는 파일을 설명하는 배열입니다.
{
"templateParts": [
{ "name": "header", "title": "Header", "area": "header" },
{ "name": "footer", "title": "Footer", "area": "footer" }
],
"customTemplates": [
{ "name": "page-wide", "title": "Wide Page", "postTypes": ["page"] }
]
}
name은 확장자를 뺀 파일 이름과 일치해야 합니다. parts/header.html, templates/page-wide.html 같은 식입니다. area 값도 중요합니다. 이 값이 파트를 header나 footer 랜드마크 요소로 감쌀지, 편집기가 이를 어떻게 분류할지를 결정합니다. 생략하면 분류되지 않은 파트로 취급됩니다.
customTemplates는 글 편집기의 템플릿 드롭다운에 템플릿이 나타나게 만드는 항목입니다. 이 항목이 없으면 파일은 존재하지만 아무도 선택할 수 없습니다.
빠른 진단 순서
블록 테마가 파일에 적힌 대로 스타일을 적용하지 않는다면, 다른 걸 손대기 전에 이 순서를 밟으세요.
- 소스 보기에서 생성된 전역 스타일 블록을 찾아보세요. 여러분의 변수가 거기 없다면 문제는
settings이거나 slug 오타입니다. - 변수는 있는데 쓰이지 않는다면
styles항목이 빠진 것입니다. - 둘 다 있는데도 무언가 덮어쓴다면 저장된 전역 스타일 기록을 확인하세요.
- 그다음에야 자체 스타일시트, 플러그인, 또는 병합 순서 뒤쪽에서 CSS를 주입하는 페이지 빌더를 살펴보세요.
FAQ
질문
워드프레스의 theme.json은 무엇인가요?
블록 테마 루트에 놓이는 하나의 JSON 설정 파일로, 두 가지를 담당합니다. 블록 편집기가 사용자에게 어떤 디자인 옵션을 노출할지, 그리고 기본 스타일이 무엇인지입니다. 워드프레스는 이 파일을 읽어 CSS 사용자 정의 속성과 스타일시트를 생성하고, 코어 기본값 및 사용자가 저장한 전역 스타일과 병합합니다.
theme.json의 settings와 styles는 어떻게 다른가요?
settings는 무엇을 쓸 수 있는지를 정의해 CSS 변수와 편집기 컨트롤을 만들어낼 뿐, 그 자체로는 아무것도 적용하지 않습니다. styles는 그 변수를 사용해 실제 값을 적용합니다. 팔레트에 색상을 추가해도 styles에서 참조하거나 사용자가 편집기에서 직접 고르기 전까지는 어떤 요소도 달라지지 않습니다.
theme.json을 수정했는데 프런트엔드에 반영되지 않는 이유는 무엇인가요?
거의 항상 데이터베이스에 저장된 전역 스타일이 theme.json을 덮어쓰고 있기 때문입니다. 누군가 사이트 편집기의 스타일 패널을 한 번이라도 건드리면, 저장된 그 기록이 담고 있는 모든 속성에서 우선권을 가집니다. 스타일 패널을 열고 리비전 패널에서 테마 기본값으로 되돌린 뒤 새로고침하세요. 두 번째로 의심할 대상은 파싱된 theme.json 데이터의 캐시입니다.
theme.json이 있어도 style.css 파일이 필요한가요?
필요합니다. 워드프레스는 테마 이름과 버전 등 메타데이터를 담은 테마 헤더 주석 때문에 style.css를 요구하며, 이 파일이 있어야 테마로 인식됩니다. 그 외에는 비워 두고 디자인 결정을 theme.json에 담아도 되고, theme.json으로 표현할 수 없는 부분만 소량의 CSS로 남겨도 됩니다.
theme.json에는 어떤 버전 번호를 써야 하나요?
지원하려는 최소 워드프레스 버전이 이해할 수 있는 가장 높은 버전을 쓰세요. version 키는 어떤 스키마 형태로 파싱할지를 워드프레스에 알려주며, 오래된 워드프레스는 모르는 키를 그냥 무시합니다. 구버전 설치를 대상으로 한다면 새 키가 알아서 무난하게 처리될 거라 기대하지 말고 그 버전이 지원하는 값에 머무르세요.
theme.json이 CSS를 완전히 대체하나요?
아닙니다. 프리셋, 블록 기본값, 요소 스타일, 레이아웃 너비와 여백까지는 잘 다루지만, 직접 작성하는 미디어 쿼리, 복잡한 선택자, 애니메이션, 그리고 지원 목록에 없는 가상 클래스 상태에는 대응하지 못합니다. 실제 서비스되는 블록 테마 대부분은 theme.json과 함께 크지 않은 스타일시트를 같이 배포합니다.