34. 설치형 워드프레스 자동 글 등록

워드프레스 자동 글 등록 세 가지 방식 — REST API와 응용 프로그램 비밀번호를 바탕으로 환경과 목적에 맞는 방식을 선택한다.

설치형 워드프레스 자동 글 등록 – 스킬·서브에이전트 활용 설계 가이드

이 문서는 완성한 글을 설치형(자체 호스팅) 워드프레스에 REST API로 자동 등록하는 방법을 스킬·서브에이전트·예약 실행 세 갈래로 나눠 설계하는 가이드다. Windows PowerShell과 Claude Code를 쓰는 환경을 전제로 하며, 워드프레스 관리자 화면에 로그인해 본 정도의 운영 경험만 있으면 따라올 수 있다. 인증 테스트부터 스킬 제작, 무인 발행 확장까지 층을 하나씩 쌓아 가고, 끝까지 따라 하면 /wp-post 한 줄로 글을 임시글로 올리는 스킬과 검수·정기 발행으로 넓히는 설계안이 손에 남는다.

1 – 전체 원리 한눈에 보기

자동 글 등록의 핵심은 두 가지다.

  1. 워드프레스 REST API — 워드프레스에는 관리자 화면에 로그인하지 않고도 글을 등록하는 "출입구(API)"가 기본으로 열려 있다. 주소는 내사이트주소/wp-json/wp/v2/posts다.
  2. 응용 프로그램 비밀번호(Application Password) — 이 출입구를 통과할 때 쓰는 "전용 열쇠"다. 워드프레스 5.6부터 기본 내장 기능이며, 실제 로그인 비밀번호를 노출하지 않고 API 전용 비밀번호를 따로 발급받는 방식이다.

비유하면, 관리자 화면 로그인이 "정문 출입"이라면 REST API는 "택배 전용 출입구"이고, 응용 프로그램 비밀번호는 택배 기사에게만 주는 출입 카드다. 카드가 유출되면 그 카드만 폐기하면 되므로, 본 비밀번호를 주는 것보다 안전하다.

Claude(스킬·서브에이전트)는 이 출입구로 등록 요청을 보내는 역할을 맡는다.

[내가 주제 지시] → [Claude가 글 작성] → [스킬/서브에이전트가 REST API 호출] → [워드프레스에 글 등록]

2 – 사전 준비 (워드프레스 + Windows)

2.1 – 조건 확인

  1. 워드프레스 버전이 5.6 이상이어야 한다.
  2. 사이트가 HTTPS(자물쇠 주소)여야 한다. 응용 프로그램 비밀번호는 보안상 HTTPS 사이트에서만 기본 동작한다.
  3. Windows 10 이상이면 진짜 curl(curl.exe)이 기본 내장돼 있다. 별도 설치가 필요 없다.

2.2 – Windows에서 반드시 알아야 할 함정

Windows에서 명령을 입력하기 전에 자주 걸리는 함정 두 가지를 먼저 짚는다. 이 둘을 모르면 다음 테스트가 원인 모를 오류로 막힌다.

PowerShell에서 curl이라고 치면 진짜 curl이 아니라 Invoke-WebRequest라는 다른 명령의 별명(alias)이 실행된다. 그래서 --user 같은 curl 옵션을 이해하지 못하고 오류가 난다. 항상 curl.exe라고 확장자까지 붙여 쓰면 진짜 curl이 실행된다.

인터넷 예제에 자주 나오는 (역슬래시)로 줄을 나누는 방식은 리눅스 문법이라 PowerShell에서는 통하지 않는다. curl이 를 별개의 접속 주소로 착각해 URL rejected: Bad hostname 오류를 낸다. 모든 명령은 한 줄로 입력한다.

2.3 – 응용 프로그램 비밀번호 발급

  1. 워드프레스 관리자 화면에 로그인한다.
  2. [사용자] → [프로필]로 이동한다.
  3. 페이지 아래쪽 [응용 프로그램 비밀번호] 항목에서 이름(예: claude-auto-post)을 입력하고 [새 응용 프로그램 비밀번호 추가]를 클릭한다.
  4. abcd efgh ijkl mnop qrst uvwx 형태(공백 포함 24자)의 비밀번호가 단 한 번 나타난다. 즉시 복사해 안전한 곳에 보관한다. 잃어버리면 폐기 후 재발급하면 된다.

2.4 – 1차 테스트 – 인증 확인

PowerShell에서 한 줄로 실행한다.

curl.exe --user "아이디:abcd efgh ijkl mnop qrst uvwx" "https://내사이트주소/wp-json/wp/v2/users/me?context=edit"

"username":"내아이디", "roles":["administrator"]가 포함된 JSON이 출력되면 인증 성공이다. 401 오류가 나면 6장을 먼저 해결한다.

2.5 – 2차 테스트 – 임시글 등록 확인

본문을 명령에 직접 넣으면 따옴표·한글이 깨지기 쉬우므로, JSON 파일로 전달하는 방식을 표준으로 삼는다.

  1. 메모장을 열어 아래 내용을 입력하고 바탕화면에 "post.json"으로 저장한다. 저장할 때 파일 형식은 "모든 파일", 인코딩은 UTF-8을 선택한다.
{"title":"API 자동 등록 테스트","content":"REST API로 등록한 테스트 글입니다.","status":"draft"}
  1. PowerShell에서 바탕화면으로 이동한 뒤 한 줄로 실행한다.
cd $env:USERPROFILE\Desktop
curl.exe -X POST "https://내사이트주소/wp-json/wp/v2/posts" --user "아이디:응용프로그램비밀번호" -H "Content-Type: application/json" --data-binary "@post.json"
  1. 응답 JSON에 "id":숫자와 "status":"draft"가 나오면 성공이다. 관리자 화면 → 글 → 임시글에서 확인한다.

이 두 테스트를 건너뛰고 스킬부터 만들면, 나중에 오류가 스킬 문제인지 서버 문제인지 구분할 수 없게 된다. 인증·등록이 확인된 뒤에 스킬을 얹는다.

3 – 방법 1 – 스킬(SKILL.md)로 만들기 (권장 시작점)

스킬은 자주 반복하는 작업 절차를 파일로 저장해 두고 /이름으로 불러 쓰는 기능이다. 글 등록처럼 절차가 고정된 작업에 가장 잘 맞는다.

3.1 – 폴더 구조 (Windows 경로)

C:\Users\내계정\.claude\skills\wp-post
├── SKILL.md       ← 절차 지시서 (필수)
└── scripts
    └── post.ps1   ← 실제 등록 스크립트 (PowerShell)

접속 정보는 스킬 폴더가 아니라 별도 폴더에 둔다.

C:\Users\내계정\.wp-secrets\env.ps1   ← 사이트 주소, 아이디, 비밀번호

접속 정보를 분리하는 이유는 다음과 같다. SKILL.md는 대화에 통째로 로드되고, 프로젝트 폴더에 넣으면 git에 올라갈 수 있다. 비밀번호를 SKILL.md에 직접 적는 것은 열쇠를 현관문에 붙여 두는 것과 같다.

3.2 – 접속 정보 파일 env.ps1

메모장으로 아래 내용을 작성해 C:\Users\내계정\.wp-secrets\env.ps1로 저장한다(인코딩 UTF-8). 비밀번호는 대화·화면에 노출된 적 없는 새로 발급받은 것을 넣는다.

$WP_URL    = "https://내사이트주소"
$WP_USER   = "아이디"
$WP_APP_PW = "abcd efgh ijkl mnop qrst uvwx"

3.3 – 등록 스크립트 scriptspost.ps1

param(
    [Parameter(Mandatory = $true)][string]$Title,
    [Parameter(Mandatory = $true)][string]$BodyFile,
    [string]$Status = "draft"   # 지정하지 않으면 draft(임시글)로 안전하게 저장
)

# 접속 정보 불러오기
. "$env:USERPROFILE\.wp-secrets\env.ps1"

# 본문 파일을 UTF-8로 읽기
$content = Get-Content -Path $BodyFile -Raw -Encoding UTF8

# JSON 조립 — ConvertTo-Json이 따옴표·줄바꿈·한글을 자동으로 안전하게 처리
$payload = @{ title = $Title; content = $content; status = $Status } | ConvertTo-Json -Depth 3

# 한글 깨짐 방지를 위해 BOM 없는 UTF-8 임시 파일로 저장 후 전송
$tmp = [System.IO.Path]::GetTempFileName()
[System.IO.File]::WriteAllText($tmp, $payload, (New-Object System.Text.UTF8Encoding($false)))

curl.exe -sS -X POST "$WP_URL/wp-json/wp/v2/posts" --user "${WP_USER}:${WP_APP_PW}" -H "Content-Type: application/json" --data-binary "@$tmp"

Remove-Item $tmp

본문을 명령 문자열에 직접 끼워 넣지 않고 세 단계로 처리한다. 파일로 읽고, ConvertTo-Json으로 조립하고, BOM 없는 UTF-8 파일로 전달한다. 이 세 단계가 따옴표 깨짐, 한글 깨짐, JSON 문법 오류를 원천 차단한다. BOM이란 일부 편집기가 파일 맨 앞에 몰래 붙이는 보이지 않는 표식으로, 서버가 JSON을 읽을 때 오류를 일으킬 수 있다.

3.4 – 스킬 지시서 SKILL.md

---
name: wp-post
description: 완성된 글을 설치형 워드프레스에 REST API로 등록한다. 글 발행, 워드프레스 업로드 요청 시 사용.
disable-model-invocation: true
argument-hint: "[제목] [상태(draft|publish)]"
allowed-tools: Bash(powershell *)
---

워드프레스 글 등록 절차:

1. 등록할 글 본문을 현재 폴더에 post-body.md 파일로 UTF-8 인코딩으로 저장한다.
   본문은 마크다운 또는 HTML로 작성한다.
2. 아래 명령으로 등록한다. 상태를 지정하지 않으면 draft(임시글)로 저장한다.
   powershell -ExecutionPolicy Bypass -File "${CLAUDE_SKILL_DIR}/scripts/post.ps1" -Title "$0" -BodyFile post-body.md -Status "$1"
3. 결과 JSON의 link(글 주소)와 status를 사용자에게 보고한다.
4. 오류가 나면 응답 본문을 그대로 보여 주고, 401이면 인증 문제임을 알린다.

3.5 – 설계 포인트 설명

  1. disable-model-invocation: true — Claude가 "글이 다 된 것 같으니" 하고 멋대로 발행하지 못하게 막고, 반드시 사용자가 /wp-post를 입력해야만 실행되게 한다. 발행은 되돌리기 번거로운 작업이므로 사람이 방아쇠를 쥐는 편이 안전하다.
  2. 기본 상태를 draft(임시글)로 둔다. 자동화 사고의 대부분은 검토 전에 공개되는 것이다. 임시글로 올린 뒤 관리자 화면에서 확인하고 발행하는 습관이 사고를 막는다.
  3. -ExecutionPolicy Bypass — Windows는 기본적으로 PowerShell 스크립트 파일(.ps1) 실행을 막아 둔다. 이 옵션은 지금 이 명령 한 번에 한해서만 실행을 허용하는 안전한 방법이다.

사용 예: /wp-post "7월 강의 후기" publish

4 – 방법 2 – 서브에이전트로 만들기

서브에이전트는 별도의 작업 지시서를 가진 부하 직원이다. 본 대화의 문맥을 어지럽히지 않고 독립된 창(컨텍스트)에서 일한 뒤 결과만 보고한다.

4.1 – 언제 스킬 대신 서브에이전트인가

  1. 등록 전 검수까지 맡기고 싶을 때다. 맞춤법·제목 길이·카테고리 확인 후 등록처럼 판단 단계가 낀 경우다.
  2. 여러 글을 병렬로 등록할 때다. 글 10개를 동시에 처리한다.
  3. 본 대화를 깨끗하게 유지하고 싶을 때다. API 응답 JSON 같은 잡음을 본 대화에 남기지 않는다.

단순히 완성된 글 1개를 등록한다면 스킬만으로 충분하다. 서브에이전트는 도구가 아니라 일꾼이므로, 절차가 단순할수록 스킬이 가볍고 빠르다.

4.2 – 서브에이전트 정의 파일 C:\Users\내계정\.claude\agents\wp-publisher.md

---
name: wp-publisher
description: 완성된 원고를 검수한 뒤 워드프레스에 REST API로 등록하는 발행 담당자. 워드프레스 등록·발행 요청 시 사용.
tools: Read, Bash
---

너는 워드프레스 발행 담당자다.

1. 전달받은 원고 파일을 읽고 다음을 점검한다:
   제목 60자 이내, 본문에 깨진 마크다운 없음, 빈 본문 아님.
2. 점검 통과 시 아래 명령으로 등록한다. 별도 지시가 없으면 상태는 draft로 한다.
   powershell -ExecutionPolicy Bypass -File "%USERPROFILE%\.claude\skills\wp-post\scripts\post.ps1" -Title "제목" -BodyFile 원고파일 -Status draft
3. 점검 실패 시 등록하지 말고 실패 사유만 보고한다.
4. 최종 보고는 "글 ID, 상태, 링크" 세 줄로만 한다.

이후 대화에서 "이 글 wp-publisher로 등록해줘"라고 하면 Claude가 이 부하 직원을 호출한다.

4.3 – 절충안 – 스킬을 서브에이전트 안에서 실행

SKILL.md 머리말에 context: fork 한 줄을 추가하면, 스킬 절차가 자동으로 독립 컨텍스트에서 실행된다. 스킬의 간편함과 서브에이전트의 격리를 함께 얻는 방법으로, 별도 agents 파일 관리가 부담스러우면 이 방식이 가장 간단하다.

5 – 방법 3 – 정기 자동 발행으로 확장

"매주 월요일 아침 9시에 이번 주 강의 안내 글 발행"처럼 시간표 기반 자동화는, 위에서 만든 스킬을 예약 실행 기능(scheduled tasks / routines)이 주기적으로 호출하게 구성한다.

  1. 예약 프롬프트 예시: "wp-post 스킬 절차에 따라, 이번 주 강의 일정 안내 글을 작성해 draft로 등록하라."
  2. 예약 실행은 매번 새 세션에서 시작되므로, 개인 스킬 폴더의 스킬이 그 환경에서도 보이는지 먼저 확인한다. 클라우드 예약 실행이라면 스킬을 계정에 등록하거나 저장소의 .claude\skills\에 넣는다.
  3. 무인 실행에서는 disable-model-invocation: true인 스킬이 자동 호출되지 않을 수 있으므로(사람 호출 전용 잠금), 정기 발행용으로는 잠금 없는 별도 스킬(예: wp-post-scheduled, 상태는 draft 고정)을 하나 더 두는 편이 안전하다.
  4. 무인 발행은 draft로만 올리고, 사람이 아침에 확인한 뒤 발행 버튼을 누르는 "반자동"부터 시작한다.

6 – 자주 나는 오류와 원인 (실제 발생 사례 포함)

6.1 – PowerShell에서 –user 인수 오류

실제 테스트에서 나온 오류다.

Invoke-WebRequest : '...' 인수를 허용하는 위치 매개 변수를 찾을 수 없습니다.

원인은 PowerShell의 curl이 진짜 curl이 아니라 Invoke-WebRequest의 별명이라서 curl 옵션을 모르는 것이다. curl.exe로 실행하면 해결된다.

6.2 – curl: (3) URL rejected: Bad hostname

실제 테스트에서 나온 오류다. 원인은 리눅스용 줄바꿈 기호 가 명령에 남아 있어, curl이 를 별개의 접속 주소로 착각한 것이다. 인증 요청 자체는 성공했더라도 이 경고가 함께 출력된다. 명령을 한 줄로 입력하면 해결된다.

6.3 – 401 Unauthorized (인증 실패)

가장 흔한 원인은 서버가 인증 정보를 PHP까지 전달하지 않고 중간에서 버리는 것이다. Apache + FastCGI 환경에서 자주 발생한다. 서버의 .htaccess에서 RewriteEngine On 아래에 다음 한 줄을 추가하면 해결되는 경우가 많다.

RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

그 외 원인은 비밀번호 24자(공백 포함)를 중간에 잘라먹은 경우, 아이디 자리에 로그인 아이디가 아닌 다른 값을 쓴 경우다.

6.4 – 403 Forbidden / REST API 응답 없음

보안 플러그인(Wordfence, iThemes Security 등)이나 호스팅 방화벽이 REST API 또는 특정 IP를 차단한 경우다. 플러그인 설정에서 REST API 차단 항목을 확인하고, 자동화를 돌릴 컴퓨터의 IP를 허용 목록에 넣는다.

6.5 – 글은 등록되는데 한글·따옴표가 깨짐

본문을 명령 문자열에 직접 끼워 넣었거나, JSON 파일을 UTF-8이 아닌 인코딩으로 저장한 경우다. 3.3의 post.ps1처럼 ConvertTo-Json + BOM 없는 UTF-8 파일 전달 구조를 쓰면 원천 차단된다.

6.6 – HTTP 사이트라서 인증이 거부됨

응용 프로그램 비밀번호는 HTTPS 전제 기능이다. 우회 설정보다 무료 인증서(Let's Encrypt)로 HTTPS를 적용하는 것이 정답이다.

7 – 세 방법 비교와 추천 경로

구분스킬서브에이전트예약 실행 조합
성격절차 지시서독립 일꾼시간표 자동화
적합한 일완성 글 즉시 등록검수 포함·다건 병렬정기 발행
난이도낮음중간중간
사람 개입/wp-post 입력요청 시없음(무인)

추천 학습 순서는 2.4 인증 테스트 → 2.5 임시글 등록 테스트 → 방법 1 스킬로 draft 등록 → 필요해지면 방법 2로 검수 단계 추가 → 마지막에 방법 3 무인 발행이다. 한 번에 무인 발행까지 가려다 실패하면 어느 층에서 문제인지 찾기 어렵다. 층을 하나씩 쌓아야 디버깅이 쉽다.

8 – 보안 마무리 점검

  1. 테스트 과정에서 채팅·화면·강의 자료 등에 노출된 응용 프로그램 비밀번호는 프로필에서 폐기(Revoke)하고 새로 발급받는다.
  2. 비밀번호는 env.ps1 한 곳에만 두고, SKILL.md·대화·git에는 적지 않는다.
  3. 자동화 전용으로 편집자(Editor) 권한 계정을 따로 만들어 쓰면, 열쇠가 유출돼도 플러그인 설치·사용자 관리 같은 관리자 권한까지는 넘어가지 않는다.

부록 – 리눅스·맥 사용자용 등록 스크립트 (참고)

서버나 맥에서 같은 작업을 할 경우의 bash 버전이다. jq가 필요하다(sudo apt install jq).

#!/bin/bash
# 사용법: post.sh "제목" 본문파일.md [publish|draft]
set -e
source ~/.wp-secrets/env

TITLE="$1"; BODY_FILE="$2"; STATUS="${3:-draft}"

JSON=$(jq -n --arg title "$TITLE" --rawfile content "$BODY_FILE" --arg status "$STATUS" \
  '{title:$title, content:$content, status:$status}')

curl -sS -X POST "$WP_URL/wp-json/wp/v2/posts" \
  --user "$WP_USER:$WP_APP_PW" \
  -H "Content-Type: application/json" \
  -d "$JSON" | jq '{id, status, link}'

참고 자료

댓글 남기기