페이지 템플릿 시스템의 사용 방법을 단계별로 설명합니다.

1. JSON 필드 추가하고 적용하는 방법
필드 설정 방법
템플릿 생성/수정 페이지의 "템플릿 설정" 탭에서 "필드 설정 (JSON)" 영역에 필드를 정의합니다.
필드 설정 예시:
{
"title": {
"type": "text",
"label": "제목",
"required": true,
"description": "페이지의 제목을 입력하세요"
},
"ceo_name": {
"type": "text",
"label": "대표이사 이름",
"required": false
},
"message": {
"type": "textarea",
"label": "인사말 내용",
"required": true,
"description": "여러 줄로 작성할 수 있습니다"
},
"ceo_image": {
"type": "image",
"label": "대표이사 사진",
"required": false,
"description": "이미지 URL을 입력하세요"
}
}
필드 타입
| 타입 | 설명 | 사용 예시 |
|---|---|---|
text |
한 줄 입력 | 제목, 이름, URL 등 |
textarea |
여러 줄 입력 | 긴 내용, 설명 등 |
image |
이미지 URL | 사진, 로고, 배너 등 |
필드 속성
| 속성 | 타입 | 설명 |
|---|---|---|
type |
string | 필드 타입 (text/textarea/image) |
label |
string | 사용자에게 표시될 라벨 |
required |
boolean | 필수 입력 여부 (true/false) |
description |
string | 필드 설명 (선택사항) |
자동 적용되는 방법
- 필드 설정을 저장하면 간편 편집기가 자동으로 생성됩니다
- 간편 편집기에서 입력한 내용은 자동으로 **기본 데이터 (JSON)**로 동기화됩니다
- 페이지 생성 시 해당 템플릿을 선택하면 정의된 필드들이 입력 폼으로 나타납니다
2. 내용에서 사용 가능한 HTML 태그
허용되는 태그
템플릿 내용에서 다음 HTML 태그들을 사용하여 스타일링할 수 있습니다:
텍스트 서식
<strong>,<b>- 굵은 글씨<em>,<i>- 이탤릭체<u>- 밑줄<mark>- 하이라이트<small>- 작은 글씨<del>,<s>-취소선<sup>- 위 첨자<sub>- 아래 첨자
구조
<p>- 문단<div>- 블록 영역<span>- 인라인 영역<br>- 줄바꿈<hr>- 수평선
제목
<h1>,<h2>,<h3>,<h4>,<h5>,<h6>- 제목 태그
목록
<ul>,<ol>,<li>- 순서 없는/있는 목록<dl>,<dt>,<dd>- 정의 목록
이미지 및 미디어
<img>- 이미지<a>- 링크<iframe>- 외부 콘텐츠 (YouTube 등)
표
<table>,<thead>,<tbody>,<tr>,<th>,<td>- 표
기타
<blockquote>- 인용문<cite>- 출처<code>,<pre>- 코드 블록
사용 예시
<div class="greeting-message">
<h2>환영합니다!</h2>
<p>저희 회사를 <strong>방문해 주셔서</strong> 감사합니다.</p>
<p>주요 특징:</p>
<ul>
<li><strong>전문성</strong>: 20년 이상의 경험</li>
<li><strong>신뢰성</strong>: 고객 만족도 95%</li>
<li><em>혁신</em>: 최신 기술 도입</li>
</ul>
<blockquote>
"고객의 성공이 우리의 성공입니다"
</blockquote>
</div>
WARNING
<script> 태그나 위험한 JavaScript는 보안상 제한될 수 있습니다.
3. 외부 CSS로 스타일링하는 방법
현재 방식: 인라인 CSS (템플릿 내부)
현재 시스템은 각 템플릿 파일에 <style> 태그를 사용하여 CSS를 포함합니다:
<div class="greeting-template">
<!-- 내용 -->
</div>
<style>
.greeting-template {
padding: 60px 0;
}
.greeting-header {
display: flex;
align-items: center;
margin-bottom: 40px;
}
/* ... 더 많은 스타일 */
</style>
권장 방식: 템플릿별 CSS 파일
템플릿마다 전용 CSS 파일을 만들어 관리하는 것이 더 좋습니다:
1. CSS 파일 구조 제안
templates/
page_templates/
greeting_basic.php
greeting_basic.css ← 템플릿 전용 CSS
history_timeline.php
history_timeline.css ← 템플릿 전용 CSS
contact_info.php
contact_info.css ← 템플릿 전용 CSS
2. 템플릿에서 CSS 로드하기
템플릿 PHP 파일에서 CSS 파일을 연결:
<?php
// 템플릿 데이터 가져오기
$pageData = $data['data'] ?? [];
$templateConfig = $data['config'] ?? [];
?>
<!-- CSS 파일 로드 -->
<link rel="stylesheet" href="/templates/page_templates/greeting_basic.css">
<div class="greeting-template">
<div class="container">
<!-- 템플릿 내용 -->
</div>
</div>
3. CSS 파일 예시 (greeting_basic.css)
.greeting-template {
padding: 60px 0;
background: #f8f9fa;
}
.greeting-header {
display: flex;
align-items: center;
margin-bottom: 40px;
gap: 30px;
}
.ceo-image img {
width: 150px;
height: 150px;
border-radius: 50%;
object-fit: cover;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.greeting-content h1 {
margin: 0 0 10px 0;
color: #333;
font-size: 2.5rem;
font-weight: 700;
}
@media (max-width: 768px) {
.greeting-header {
flex-direction: column;
text-align: center;
}
}
전역 CSS vs 템플릿 CSS
| 구분 | 위치 | 용도 |
|---|---|---|
| 전역 CSS |
|
모든 페이지에 공통 적용되는 스타일 |
| 템플릿 CSS | templates/page_templates/[템플릿명].css |
특정 템플릿에만 적용되는 스타일 |
전역 CSS 예시
/* assets/css/common.css */
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.btn {
padding: 10px 20px;
border-radius: 4px;
border: none;
cursor: pointer;
}
4. 이미지 타입 필드 사용 방법
이미지 필드 정의
{
"ceo_image": {
"type": "image",
"label": "대표이사 사진",
"required": false,
"description": "이미지 URL을 입력하거나 업로드하세요"
},
"company_logo": {
"type": "image",
"label": "회사 로고",
"required": true
}
}
템플릿에서 이미지 사용
<?php if (!empty($pageData["ceo_image"])): ?>
<div class="ceo-image">
<img src="<?= htmlspecialchars($pageData["ceo_image"]) ?>"
alt="대표이사"
class="img-responsive">
</div>
<?php endif; ?>
이미지 업로드 기능 추가 (권장 개선사항)
현재는 URL을 직접 입력하는 방식이지만, 다음과 같이 개선할 수 있습니다:
개선된 이미지 입력 UI
<div class="form-group">
<label>대표이사 사진</label>
<div class="image-upload-wrapper">
<input type="text"
class="easy-input"
data-key="ceo_image"
value=""
placeholder="이미지 URL을 입력하거나 파일을 업로드하세요">
<button type="button"
class="btn btn-secondary"
onclick="openImageUpload('ceo_image')">
<i class="fas fa-upload"></i> 파일 선택
</button>
</div>
<!-- 이미지 미리보기 -->
<div class="image-preview" id="preview_ceo_image" style="display:none;">
<img src="" alt="미리보기" style="max-width: 200px; margin-top: 10px;">
<button type="button"
class="btn btn-sm btn-danger"
onclick="removeImage('ceo_image')">
<i class="fas fa-times"></i> 제거
</button>
</div>
</div>
이미지 업로드 JavaScript
function openImageUpload(fieldKey) {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'image/*';
input.onchange = async (e) => {
const file = e.target.files[0];
if (!file) return;
// 파일 업로드
const formData = new FormData();
formData.append('image', file);
try {
const response = await fetch('/ajax/upload_image.php', {
method: 'POST',
body: formData
});
const result = await response.json();
if (result.success) {
// 업로드된 이미지 URL을 필드에 설정
const inputField = document.querySelector(`[data-key="${fieldKey}"]`);
inputField.value = result.url;
// 미리보기 표시
showImagePreview(fieldKey, result.url);
// JSON 동기화
syncToJSON();
} else {
alert('이미지 업로드 실패: ' + result.message);
}
} catch (error) {
alert('업로드 중 오류가 발생했습니다.');
}
};
input.click();
}
function showImagePreview(fieldKey, imageUrl) {
const preview = document.getElementById(`preview_${fieldKey}`);
const img = preview.querySelector('img');
img.src = imageUrl;
preview.style.display = 'block';
}
function removeImage(fieldKey) {
const inputField = document.querySelector(`[data-key="${fieldKey}"]`);
inputField.value = '';
const preview = document.getElementById(`preview_${fieldKey}`);
preview.style.display = 'none';
syncToJSON();
}
실전 예시: 회사 소개 템플릿
1. 필드 설정
{
"company_name": {
"type": "text",
"label": "회사명",
"required": true
},
"slogan": {
"type": "text",
"label": "슬로건",
"required": false
},
"company_logo": {
"type": "image",
"label": "회사 로고",
"required": false
},
"introduction": {
"type": "textarea",
"label": "회사 소개",
"required": true,
"description": "HTML 태그를 사용하여 스타일링할 수 있습니다"
},
"ceo_image": {
"type": "image",
"label": "대표이사 사진",
"required": false
},
"ceo_name": {
"type": "text",
"label": "대표이사 이름",
"required": false
},
"ceo_message": {
"type": "textarea",
"label": "대표 인사말",
"required": false
}
}
2. 템플릿 PHP 파일 (company_intro.php)
<?php
$pageData = $data['data'] ?? [];
$templateConfig = $data['config'] ?? [];
?>
<link rel="stylesheet" href="/templates/page_templates/company_intro.css">
<div class="company-intro-template">
<div class="container">
<!-- 헤더 섹션 -->
<div class="company-header">
<?php if (!empty($pageData["company_logo"])): ?>
<img src="<?= htmlspecialchars($pageData["company_logo"]) ?>"
alt="<?= htmlspecialchars($pageData["company_name"] ?? '') ?>"
class="company-logo">
<?php endif; ?>
<h1><?= htmlspecialchars($pageData["company_name"] ?? "회사명") ?></h1>
<?php if (!empty($pageData["slogan"])): ?>
<p class="slogan"><?= htmlspecialchars($pageData["slogan"]) ?></p>
<?php endif; ?>
</div>
<!-- 회사 소개 -->
<div class="company-introduction">
<?= $pageData["introduction"] ?? "" ?>
</div>
<!-- CEO 인사말 -->
<?php if (!empty($pageData["ceo_message"])): ?>
<div class="ceo-section">
<h2>대표 인사말</h2>
<div class="ceo-content">
<?php if (!empty($pageData["ceo_image"])): ?>
<div class="ceo-image">
<img src="<?= htmlspecialchars($pageData["ceo_image"]) ?>"
alt="<?= htmlspecialchars($pageData["ceo_name"] ?? '대표이사') ?>">
</div>
<?php endif; ?>
<div class="ceo-message">
<?= nl2br(htmlspecialchars($pageData["ceo_message"])) ?>
<?php if (!empty($pageData["ceo_name"])): ?>
<p class="ceo-name"><?= htmlspecialchars($pageData["ceo_name"]) ?></p>
<?php endif; ?>
</div>
</div>
</div>
<?php endif; ?>
</div>
</div>
3. 템플릿 CSS 파일 (company_intro.css)
.company-intro-template {
padding: 80px 0;
background: linear-gradient(to bottom, #f8f9fa 0%, #ffffff 100%);
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* 헤더 */
.company-header {
text-align: center;
margin-bottom: 60px;
}
.company-logo {
max-width: 200px;
height: auto;
margin-bottom: 20px;
}
.company-header h1 {
font-size: 3rem;
font-weight: 700;
color: #1a1a1a;
margin: 20px 0 10px;
}
.slogan {
font-size: 1.3rem;
color: #666;
font-style: italic;
}
/* 회사 소개 */
.company-introduction {
background: white;
padding: 40px;
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
margin-bottom: 60px;
line-height: 1.8;
font-size: 1.1rem;
}
/* CEO 섹션 */
.ceo-section {
background: white;
padding: 40px;
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.ceo-section h2 {
text-align: center;
font-size: 2rem;
margin-bottom: 40px;
color: #333;
}
.ceo-content {
display: flex;
gap: 40px;
align-items: flex-start;
}
.ceo-image img {
width: 200px;
height: 200px;
border-radius: 50%;
object-fit: cover;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
.ceo-message {
flex: 1;
font-size: 1.1rem;
line-height: 1.8;
color: #555;
}
.ceo-name {
margin-top: 30px;
font-size: 1.3rem;
font-weight: 600;
color: #333;
text-align: right;
}
/* 반응형 */
@media (max-width: 768px) {
.company-header h1 {
font-size: 2rem;
}
.company-introduction,
.ceo-section {
padding: 20px;
}
.ceo-content {
flex-direction: column;
align-items: center;
text-align: center;
}
.ceo-name {
text-align: center;
}
}
4. 사용자가 입력하는 내용 예시
<div class="intro-content">
<h2>회사 비전</h2>
<p><strong>혁신</strong>과 <strong>신뢰</strong>를 바탕으로 <em>더 나은 미래</em>를 만들어갑니다.</p>
<h3>핵심 가치</h3>
<ul>
<li><strong>고객 중심</strong>: 고객의 성공이 우리의 성공</li>
<li><strong>창의성</strong>: 끊임없는 혁신과 도전</li>
<li><strong>책임감</strong>: 약속을 지키는 기업</li>
</ul>
<blockquote>
"우리는 단순히 제품을 판매하는 것이 아니라, <mark>가치를 전달</mark>합니다."
</blockquote>
</div>
요약
✅ 해야 할 것
- 필드 설정을 먼저 정의 - JSON 형식으로 필드와 타입 지정
- HTML 태그 활용 - 내용에 다양한 태그를 사용하여 스타일링
- 템플릿별 CSS 파일 분리 - 유지보수가 쉽고 깔끔한 코드
- 이미지 타입 필드 사용 - URL 입력 또는 파일 업로드 (개선 필요)
⚠️ 주의할 것
- JSON 형식이 정확해야 간편 편집기가 작동합니다
- 보안상 위험한
<script>태그는 사용하지 마세요 - 이미지는 절대 URL 또는 상대 경로를 정확히 입력하세요
- CSS 클래스명은 템플릿끼리 충돌하지 않도록 고유하게 지정하세요
🚀 개선 제안
- 이미지 업로드 기능 추가 - URL 입력 대신 파일 업로드 버튼
- WYSIWYG 에디터 통합 - textarea 필드에 TinyMCE 연동
- CSS 파일 자동 연결 - 템플릿 ID와 동일한 이름의 CSS 자동 로드
- 필드 타입 확장 - select, checkbox, date 등 추가
댓글 0개