이미지를 업로드하고 게시물에 연결하기 (커스텀 필드 활용)
이제 다시 글쓰기로 돌아와 사용자들이 글을 작성할 때 이미지를 함께 업로드할 수 있도록 구현할 것입니다.짧은 텍스트 중심의 트위터 스타일 웹 앱이지만, 이미지가 추가되면 콘텐츠의 전달력과 몰입도가 확실히 달라집니다. 그래서 간단하면서도 직관적인 이미지 업로드 기능을 구현해봤습니다.
워드프레스에서 대표 이미지(featured_media)는 하나만 설정할 수 있고, 본문(content)에 이미지를 삽입하면 편집이 불편하며 구조적으로 깔끔하게 데이터를 관리하기 어렵습니다.
저는 이미지 URL을 별도로 저장하고, 클라이언트에서 해당 필드를 이용해 이미지를 깔끔하게 렌더링하는 구조를 원했습니다. 예를 들어, 다음과 같은 형태로 이미지를 저장하고 사용하는 것이죠:
"meta": { "image_urls": [ "https://myDomain.com/uploads/image1.jpg", "https://myDomain.com/uploads/image2.jpg", "https://myDomain.com/uploads/image3.jpg" ] }
이 문제를 해결하기 위해 저는 image_urls라는 커스텀 메타 필드를 등록해주는 전용 플러그인을 따로 만들어 사용합니다.
이 플러그인의 역할은 단순히 image_urls라는 메타 필드를 REST API에 노출시키는 것입니다.
custom-image-meta.zip 0.00MB
👉 이 플러그인은 워드프레스 관리자 > 플러그인 > 새로 추가 > 업로드 를 통해 설치한 뒤 활성화하면 바로 사용할 수 있습니다.
<textarea id="postContent" placeholder="무슨 일이 일어나고 있나요?"></textarea> <input type="file" id="imageUpload" multiple style="display: none" /> <button id="customUploadBtn" type="button">이미지 선택</button> <div id="preview"></div> <p id="fileStatus">0장의 이미지 선택됨</p> <button id="postButton" onclick="submitPost()">게시하기</button> <p id="loading" class="loading" style="display: none"> 이미지 업로드 중...<span id="progress">0/0</span> </p>
1. input[type="file"]은 숨겨두고, 버튼으로 클릭 유도
2. 미리보기(preview) 영역에 이미지와 삭제 버튼 표시
3. 업로드 진행 상태도 progress로 표시
이미지를 선택하면 미리보기로 보여주고, 개별 삭제도 가능하게 처리합니다.
let selectedImages = []; function renderPreview() { const preview = document.getElementById('preview'); preview.innerHTML = ''; selectedImages.forEach((file, index) => { const reader = new FileReader(); reader.onload = function (e) { const img = document.createElement('img'); img.src = e.target.result; img.style.width = '80px'; img.style.height = '80px'; img.style.objectFit = 'cover'; const removeBtn = document.createElement('button'); removeBtn.innerText = '❌'; removeBtn.onclick = () => { selectedImages.splice(index, 1); renderPreview(); }; const container = document.createElement('div'); container.style.display = 'inline-block'; container.style.position = 'relative'; container.appendChild(img); container.appendChild(removeBtn); preview.appendChild(container); }; reader.readAsDataURL(file); }); fileStatus.innerText = `${selectedImages.length}장의 이미지 선택됨`; }
fetch로 워드프레스의 Media API에 직접 이미지를 업로드합니다. 이 과정에서 JWT 토큰을 사용해 인증을 처리하고, 업로드된 이미지의 source_url을 반환받습니다.
async function uploadImage(file, index, total) { const formData = new FormData(); formData.append('file', file); formData.append('title', file.name); formData.append('status', 'publish'); document.getElementById('progress').innerText = `${index}/${total}`; const response = await fetch(mediaApiUrl, { method: 'POST', headers: { Authorization: `Bearer ${token}` }, body: formData }); if (response.ok) { const data = await response.json(); return data.source_url; } else { alert(`이미지 ${index} 업로드 실패!`); return null; } }
이미지 업로드가 끝나면 해당 URL들을 배열로 모아서 게시물에 저장하고 REST API에 커스텀 메타 필드로 전달을 합니다.
const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, body: JSON.stringify({ title: `${userSlug}-${getCurrentTimestamp()}`, content, status: 'publish', meta: { image_urls: JSON.stringify(imageUrls), }, }), });