WordPress 자동 발행이 조용히 터지는 순간 — 제가 겪은 함정 3가지와 해결법

자동화 파이프라인을 처음 완성했을 때, 저는 꽤 자신만만했습니다. Make.com 시나리오가 돌아가고, Claude API가 글을 생성하고, Flask가 WordPress REST API로 밀어넣는 구조. 테스트 발행도 성공. 그런데 실제 운영 첫 주, 글이 초안 상태로 멈춰있었습니다. 발행된 게 아니라 draft로 쌓이고 있었던 겁니다. 조용히, 아무 에러 로그도 없이. 그게 이 파이프라인이 저에게 가르쳐준 첫 번째 교훈이었습니다. 자동화는 터질 때 소리를 내지 않는다.

함정 1 — REST API 인증 토큰이 조용히 만료된다

WordPress REST API를 쓸 때 Application Password 방식을 많이 씁니다. 저도 처음엔 그걸 썼는데, 문제는 토큰 자체가 만료되지 않는 대신 계정 비밀번호 변경, 보안 플러그인 충돌, 또는 서버 이전 시 자동으로 무효화된다는 점입니다. 무효화되면 WordPress는 401 Unauthorized를 반환하는데, Make.com 시나리오가 이 응답을 에러로 처리하지 않고 그냥 넘어가버리는 경우가 있었습니다. 구체적으로는 HTTP 모듈의 에러 핸들링이 4xx를 성공으로 간주하도록 잘못 설정되어 있었던 게 원인이었습니다. 해결책은 두 가지였습니다. 첫째, Make.com HTTP 모듈에서 ‘2xx 이외 응답을 에러로 처리’ 옵션을 명시적으로 켜는 것. 설정 위치는 HTTP 모듈 고급 설정 안의 Parse response 항목입니다. 둘째, Flask 쪽에서도 WordPress API 응답 status code를 직접 체크하고, 201이 아닌 경우 Slack 웹훅으로 알림을 보내도록 했습니다. 코드로는 if response.status_code != 201: requests.post(slack_url, json={‘text’: f’WP 발행 실패: {response.status_code}’}) 형태로 단순하게 넣었습니다. 이후로는 발행 실패가 15분 안에 감지됩니다.

함정 2 — Claude가 생성한 텍스트가 WordPress 필드를 오염시킨다

Claude API가 반환하는 텍스트를 그대로 WordPress content 필드에 넣으면 예상치 못한 문제가 생깁니다. 제가 겪은 가장 골치아팠던 케이스는 Claude가 본문 안에 HTML 태그를 혼용했을 때였습니다. 예를 들어 마크다운 굵게 표시인 ** 와 HTML bold 태그를 섞어 쓰는 경우, WordPress 클래식 에디터와 블록 에디터가 이걸 다르게 해석해서 화면에 태그 문자열이 그대로 출력되는 일이 있었습니다. 또 하나는 Claude가 간혹 응답 앞에 ‘물론입니다. 아래 글을 작성했습니다.’ 같은 서두를 붙이는 경우입니다. 프롬프트로 막아도 100% 막히지 않았습니다. 해결은 Flask 레이어에서 전처리를 넣는 것이었습니다. 구체적으로는 정규식으로 본문 시작부 불필요한 안내 문장을 제거하는 로직과, 마크다운을 html로 변환하는 markdown2 라이브러리를 함께 적용했습니다. pip install markdown2 후 import markdown2, 그리고 content_html = markdown2.markdown(raw_content) 한 줄로 처리합니다. 이 전처리 레이어를 넣고 나서 포맷 오류로 인한 수동 수정 작업이 사실상 사라졌습니다. Claude를 믿되, 출력은 반드시 한 번 걸러야 한다는 게 지금의 제 원칙입니다.

함정 3 — 발행 성공인데 글이 SEO 설정 없이 올라간다

WordPress REST API로 글을 올릴 때 title, content, status 세 필드만 넣으면 발행은 됩니다. 문제는 meta_description, slug, featured image, 카테고리, 태그가 전부 빠진 채로 올라간다는 점입니다. 저는 Yoast SEO를 쓰고 있는데, REST API로 Yoast 메타 필드를 함께 넣으려면 별도의 방법이 필요합니다. Yoast는 기본적으로 REST API 쓰기를 지원하지 않기 때문에, Custom Endpoint를 활성화하거나 플러그인을 추가해야 합니다. 제가 쓴 방법은 WP REST API – Yoast SEO라는 플러그인 설치 후, POST 요청 body에 yoast_wpseo_metadesc 필드를 추가하는 방식입니다. slug는 REST API의 기본 필드라 그냥 넣으면 되고, 카테고리와 태그는 categories와 tags 필드에 ID 배열로 넣어야 합니다. 이 ID를 하드코딩하지 않으려면 Flask에서 WordPress /wp/v2/categories?search=카테고리명 으로 먼저 조회해서 ID를 동적으로 가져오는 함수를 만들어야 합니다. 처음엔 귀찮아서 ID를 직접 박아넣었는데, 카테고리 하나를 실수로 삭제했다가 발행 오류가 연속으로 났습니다. 동적 조회가 결국 더 안전합니다. featured image는 별도로 /wp/v2/media 엔드포인트에 먼저 업로드하고, 반환된 ID를 featured_media 필드에 넣는 2단계 방식으로 처리합니다.

💬 운영자 한마디

자동화를 구축하면서 제가 내린 결론은, 파이프라인의 취약점은 항상 연결 지점에 있다는 겁니다. Claude도, Make.com도, Flask도 각각은 잘 작동합니다. 문제는 그 사이 어딘가에서 데이터가 변형되거나, 응답이 묵살되거나, 설정이 충돌할 때 생깁니다. 저는 지금도 새 구간을 연결할 때마다 ‘이 지점이 조용히 실패하면 어떻게 감지할 것인가’를 먼저 설계합니다.

— J_River · autoprofit 운영자

✅ 이번 주 체크리스트

  • Make.com HTTP 모듈에서 2xx 이외 응답을 에러로 처리하도록 명시 설정
  • Flask에서 WordPress API 응답 status_code를 201 기준으로 체크하고 Slack 알림 연결
  • Claude 응답 전처리 레이어 추가 — markdown2로 HTML 변환 후 서두 안내문 정규식 제거
  • Yoast SEO 메타 필드 REST API 지원 플러그인 설치 및 yoast_wpseo_metadesc 필드 연동 확인
  • 카테고리/태그 ID를 하드코딩 대신 /wp/v2/categories 동적 조회 함수로 교체
  • featured image 업로드는 /wp/v2/media 엔드포인트 2단계 방식으로 처리 후 ID를 featured_media에 주입
  • 파이프라인 각 연결 지점마다 실패 감지 로직을 먼저 설계하는 습관 유지

자동화는 완성하는 순간이 아니라 조용히 터지는 순간을 줄여가는 과정입니다. 이번 주에 소개한 세 가지 함정이 같은 고통을 겪고 있는 분들께 조금이라도 시간을 아껴주길 바랍니다. 다음 주에도 실전에서 나온 기록으로 돌아오겠습니다.

※ 본 콘텐츠는 운영자 개인의 경험과 연구를 바탕으로 한 정보 제공 목적이며, 특정 종목에 대한 투자 권유나 매매 시그널이 아닙니다. 암호화폐 및 자동매매는 원금 손실 가능성이 있는 고위험 활동이며, 모든 투자 판단과 그 결과에 대한 책임은 투자자 본인에게 있습니다.