Rank Math

  • AI 블로그 자동화, 경쟁 글 분석 기능 테스트 7개 통과시켰다

    AI 블로그 자동화, 경쟁 글 분석 기능 테스트 7개 통과시켰다

    AI 블로그 자동화 파이프라인을 돌리면서도, 정작 경쟁 글 구조는 한 번도 체계적으로 분석한 적이 없었다. 글을 잘 쓰는 것과 검색에 상위 노출되는 것은 다른 문제다.

    그 사실을 알면서도 나는 꽤 오랫동안 내 경험만 믿고 글 구조를 짰다. 경쟁자가 뭘 쓰는지는 봤지만, 그들이 어떤 흐름으로 소제목을 배치하는지는 한 번도 체계적으로 분석하지 않았다.

    AI 블로그 자동화에 왜 남의 글 구조를 참고해야 할까 (그 글들이 상위 노출된 이유)

    상위 노출된 글은 우연히 거기 있지 않다. 검색 알고리즘(검색 시스템이 글의 품질을 평가하는 방식)이 그 글을 좋다고 판단했거나, 독자들이 오래 머물렀거나, 두 가지가 동시에 일어난 것이다.

    내 블로그 자동화 파이프라인(pipeline, 여러 작업을 순서대로 연결한 처리 흐름)에는 outline-writer.ts라는 에이전트(agent, 특정 임무를 수행하는 AI 프로그램 단위)가 있었다.

    이 에이전트는 내가 제공한 인터뷰, 즉 실제 경험 데이터만 보고 글의 구조를 짰다. 네이버 검색 키워드는 미리 조사해서 넣었다. 여기까지는 괜찮았다.

    문제는 그다음이었다.

    같은 키워드로 구글과 네이버에 실제로 어떤 글이 뜨는지, 그 글들이 소제목을 어떤 순서로 배치하는지, 키워드를 어느 위치에 박아 넣는지 — 이걸 전혀 참고하지 않았다. 검색 의도(사용자가 검색할 때 실제로 원하는 정보)를 무시한 채 구조를 짠 셈이다.

    상위 노출 글의 구조는 그 자체가 데이터다. 베끼자는 게 아니다. 어떤 흐름이 먹히는지 확인하자는 것이다.

    경쟁 글 분석 에이전트를 따로 만든 이유 (구조만, 문장은 절대 아니)

    가장 먼저 정해야 할 선이 있었다. 구조를 참고하는 것과 문장을 베끼는 것은 완전히 다르다. 저작권 문제를 떠나서, 남의 문장을 그대로 가져오면 내 글이 될 수 없다.

    AI 블로그 자동화를 에이전트 하나가 다 떠맡게 하고 싶지 않았다. 그래서 새 에이전트를 따로 만들었다. agents/competitor-analyzer.ts다.

    이 에이전트가 하는 일은 하나다.

    경쟁 글에서 제목, 소제목(H2) 흐름, 키워드 배치 위치만 뽑아내는 것. 본문 문장은 가져오지 않는다. 이 제약을 코드 레벨이 아니라 프롬프트(AI에게 주는 지시문) 레벨에서 명확하게 걸었다.

    왜 outline-writer에 기능을 얹지 않고 에이전트를 새로 만들었을까. 역할이 다르기 때문이다.

    분석과 집필은 분리해야 나중에 고치기 쉽다. 하나의 에이전트가 두 가지 일을 동시에 하면, 문제가 생겼을 때 어디서 틀렸는지 찾기 어려워진다.

    web_search 도구로 상위 글 2~3개를 찾아 JSON으로 뽑기

    구현은 AI 블로그 자동화 파이프라인에서 이 부분이 핵심이다. 앤트로픽 SDK(소프트웨어 개발 키트, AI 기능을 코드에서 쓸 수 있게 해주는 도구 묶음)의 web_search 서버 도구를 사용했다.

    주제와 관련된 구글 상위 글 2~3개를 찾고, 거기서 구조 정보만 JSON(JavaScript Object Notation, 데이터를 구조화해서 저장하는 텍스트 형식)으로 추출하는 방식이다.

    모델(AI 엔진)은 claude-haiku-4-5를 썼다. outline-writer와 같은 모델이다. 여기서 한 가지 막히는 부분이 있었다.

    web_search 도구에는 두 가지 변형이 있는데, 동적 필터링(검색 조건을 더 세밀하게 조절하는 기능)을 지원하는 최신 버전인 web_search_20260209는 claude-haiku-4-5에서 쓸 수 없었다.

    기본형인 web_search_20250305만 지원됐다. 중간에 알게 돼서 맞췄다.

    pause_turn 처리와 결과물

    또 하나 신경 써야 했던 부분이 있다. 검색 도중 stop_reason(AI가 응답을 멈춘 이유)이 pause_turn으로 끊기는 경우가 생겼다.

    AI가 검색 결과를 받아오는 도중에 중간에 멈추는 현상이다. 이 경우를 처리하기 위해 최대 3번까지 재시도하는 루프를 넣었다.

    AI 블로그 자동화 파이프라인이 실제로 쓰는 데이터는 이거다. 각 경쟁 글마다 제목, H2 소제목 목록, 키워드가 등장하는 위치를 JSON 형태로 정리한 구조 데이터다. 문장은 없다. 뼈대만 있다.

    아래는 테스트가 전부 통과한 시점의 캡처다.

    AI 블로그 자동화 경쟁 글 분석 에이전트 테스트 7개 통과 터미널 캡처

    7개 테스트 파일이 모두 초록불이다. competitor-analyzer.test.ts가 새로 추가된 파일이다.

    outline-writer에 분석 결과를 선택적으로 연결하는 방법

    AI 블로그 자동화 파이프라인에서 분석과 집필을 분리한 이유가 여기서 드러난다.

    competitor-analyzer.ts가 뽑아낸 JSON 결과를 outline-writer.ts에 그냥 던져주면 안 된다. 선택적으로 연결해야 한다.

    outline-writer.ts는 이 분석 결과를 선택적 인자로 받는다.

    분석 결과가 있으면 프롬프트 안에 포함되고, 없으면 기존 방식대로 동작한다. 여기서 프롬프트 문구가 중요하다. 단순히 데이터를 붙여 넣는 게 아니라, 이런 문구를 명시한다.

    참고용 , 절대 베끼지 말고 어떤 흐름이 먹히는지만 참고

    이 한 줄이 없으면 AI는 경쟁 글의 소제목을 그대로 가져올 수 있다. 지시를 명확하게 줘야 한다.

    파이프라인 전체 흐름에서 이 단계의 위치는 이렇다. 인터뷰 데이터를 로드하고 나서, outline을 생성하기 전에 경쟁 글 분석 단계를 끼워 넣었다.

    generate.ts가 이 순서를 관리한다. 순서가 바뀌면 의미가 없다. 분석 결과가 outline보다 먼저 나와야 참고가 된다.

    인스타 숏폼에서 배운 ‘훅’과 ‘피크엔드’ 원칙을 프롬프트에 녹이기

    같은 날 인스타 릴스 영상을 하나 봤다.

    릴스 기획을 AI한테 시키는 방법을 설명하는 영상이었다. 숏폼 영상 기획 공식 세 가지를 소개했다. 도입 3초 훅, 결말 피크엔드 법칙, 중간 반전.

    릴스에서 본 걸 그대로 믿지 않고 AI 블로그 자동화 작업에 가져오기 전에 직접 검증해보는 건 이전에도 한 적이 있다.

    이 중 두 가지는 텍스트 블로그에도 쓸 수 있었다. 나머지 하나는 못 썼다.

    화면 방향 전환이나 다음 영상으로 유도하는 클리프행어는 영상 전용 요소다. 텍스트에 옮기는 건 억지다. 그래서 뺐다.

    가져온 두 가지는 이것이다.

    • 인지 부조화 훅 , 도입부에서 서로 어울리지 않는 개념을 나란히 붙이거나, 독자가 예상하지 못한 사실을 먼저 던져서 궁금증을 만든다. 읽고 싶게 만드는 첫 문장이다.
    • 피크엔드 법칙 , 결론을 흐지부지 요약하지 않는다. 글에서 가장 중요한 성과나 숫자를 마지막에 다시 한번 짚으며 끝낸다. 사람은 절정과 마지막 순간을 가장 선명하게 기억한다.

    프롬프트에 실제로 반영한 곳

    이 두 원칙을 프롬프트 문구로 만들어서 두 군데에 넣었다.

    outline-writer.ts에는 제목 작성 지침과 마지막 소제목 지침에 반영했다. content-writer.ts에는 첫 문단 작성 지침과 결론 지침에 반영했다.

    아래는 outline-writer.ts와 content-writer.ts 프롬프트에 지침이 추가된 코드 캡처다.

    AI 블로그 자동화 competitor-analyzer.ts 코드 ,  web_search 도구와 pause_turn 재시도 루프

    텍스트로 적혀 있는 지침이지만, AI가 이 문구를 받으면 실제로 첫 문단과 결론을 다르게 쓴다.

    5가지 테스트 케이스로 검증하고, 실전 테스트는 아직 남았다

    AI 블로그 자동화 기능 하나를 추가했다고 테스트를 건너뛸 수는 없다. 코드를 짜고 나서 바로 테스트를 작성했다. competitor-analyzer.test.ts다. 확인한 케이스는 다섯 가지다.

    • 프롬프트 안에 주제와 ‘그대로 가져오지 말라’는 제약 문구가 실제로 들어가는지
    • 정상적인 JSON 응답이 제대로 파싱되는지
    • posts 필드(데이터 항목)가 없을 때 빈 배열로 폴백되는지
    • 검색 결과가 아예 없을 때도 posts: []로 정상 처리되는지
    • 응답 앞뒤에 “검색해보겠습니다” 같은 설명 텍스트가 붙어도 JSON만 정확히 추출되는지

    테스트는 통과했지만, 실전은 아직

    npm test를 실행했다. 기존 6개 테스트 파일에 새 파일이 더해져 총 7개 파일이 전부 통과했다.

    솔직하게 적어야 하는 부분이 있다. 코드와 테스트는 끝났다.

    하지만 실제로 npm run generate를 돌려서 경쟁 글 분석 결과가 실전 outline에 얼마나 잘 반영되는지는 아직 확인하지 않았다. 실행 결과를 본 적이 없다. 이 부분은 모른다.

    테스트 통과와 실전 동작은 다르다. 이건 늘 그렇다. 코드가 맞아도 AI의 실제 출력이 기대와 다를 수 있다. 그걸 확인하는 것이 다음 단계다.

    이번 작업에서 실제로 이뤄진 것은 이것이다.

    경쟁 글 구조를 자동으로 분석하는 에이전트 1개 추가, 테스트 케이스 5개 작성, 총 7개 테스트 파일 전부 통과. 코드와 테스트는 여기까지 증명했다.

    그런데 outline-writer가 이 분석 결과를 실제 글쓰기에 얼마나 반영할지는 아직 모른다. npm run generate를 처음 돌렸을 때, 결과물이 기대와 같을까 다를까.

  • 관련 글 카드로 바꾸다 만난 버그 3개, 워드프레스 템플릿 직접 수정기

    관련 글 카드로 바꾸다 만난 버그 3개, 워드프레스 템플릿 직접 수정기

    이번에 손댄 건 글 상세 페이지(single 템플릿)다. 댓글창을 없애고, 관련 글 카드를 넣고, 저자 소개 박스를 추가했다. 작업 방식은 워드프레스 에디터에서 클릭하는 게 아니라 REST API(Application Programming Interface, 프로그램끼리 데이터를 주고받는 창구)로 템플릿 파일을 직접 꺼내서 코드를 고치는 방식이었다. 순서대로 정리한다.

    왜 기본 댓글창을 없앴을까?

    글 하단에 워드프레스 기본 댓글 폼(form, 입력창)이 그대로 붙어 있었다. 문제는 이걸 아무도 쓰지 않는다는 거다. 방문자가 거의 없는 블로그라 댓글이 달린 적이 한 번도 없었다. 빈 입력창이 화면 아래를 한 블록씩 차지하고 있는 셈이었다.

    없애는 건 결정했다. 그 자리에 뭘 넣을지가 문제였다. 고민 끝에 관련 글 카드 그리드로 채우기로 했다. 어차피 그 공간, 뭔가 의미 있는 걸 보여주는 게 낫다.

    REST API로 템플릿 파일을 직접 수정하는 방법

    워드프레스 블록 테마(block theme, 블록 단위로 페이지를 조립하는 방식의 테마)를 쓰면 템플릿 파일이 코드로 저장된다. 이걸 에디터에서 클릭해서 고칠 수도 있지만, 이번엔 REST API를 썼다.

    방식은 단순하다. 먼저 GET 요청(request, 서버에 데이터를 달라고 보내는 신호)으로 현재 템플릿 코드를 통째로 받아온다. 그 코드를 수정한 뒤, POST 요청으로 다시 서버에 올린다. 이번에 건드린 파일은 twentytwentyfive//single(글 상세 페이지 템플릿)과 twentytwentyfive//home(홈 페이지 템플릿) 두 개다.

    수정 전에는 반드시 원본을 백업해둬야 한다. 이건 선택이 아니다. 잘못 올리면 페이지가 깨지고, 원본이 없으면 되돌릴 방법이 없다.

    수정 후에도 주의할 게 있다. 캐시 플러그인인 LiteSpeed가 이전 버전을 그대로 보여주기 때문에, 코드를 올린 뒤 캐시를 반드시 지워야 실제로 반영된다. 이걸 모르면 코드는 바뀌었는데 화면은 그대로라 한참 헤맬 수 있다.

    바뀐 결과는 매번 데스크톱과 모바일 화면을 스크린샷으로 직접 확인했다. 눈으로 봐야 안다.

    관련 글 카드를 만들고 현재 글 중복 버그 고치기

    댓글 블록 자리에 쿼리 루프 블록을 넣었다. 카드 3개짜리 그리드다. 각 카드에는 대표 이미지, 카테고리, 제목, 날짜가 나온다.

    섹션 제목은 처음에 ‘이어서 읽을 글’이라고 썼다. 뉘앙스가 애매했다. ‘함께 보면 좋은 글’로 바꿨다.

    그런데 버그가 두 개 있었다.

    첫 번째. 지금 읽고 있는 글 자신이 관련 글 카드에 그대로 나왔다. 현재 글이 본문 위에도 있고, 아래 카드에도 있는 구조였다. 이건 WPCode 플러그인(코드 스니펫을 워드프레스에 안전하게 추가할 수 있는 도구)으로 PHP 필터를 추가해서 현재 글 ID를 쿼리에서 빼는 방식으로 해결했다.

    두 번째. 글 하단에 예전부터 있던 ‘더 많은 게시물’ 목록이 그대로 살아 있었다. 새로 넣은 카드 바로 아래에 같은 글들이 또 나오는 거다. 이건 그냥 지웠다. 살릴 이유가 없었다.

    카드 추천 로직도 손봤다. 같은 카테고리에 글이 4개 이상 있으면 그 카테고리 안에서만 추천하고, 부족하면 최신 글로 채운다.

    저자 이름 링크가 빈 페이지로 가던 문제 해결

    글 상단에 ‘작성자 JIN’이 표시되는데, ‘JIN’을 클릭하면 워드프레스 기본 작성자 아카이브 페이지인 /author/ujinify/로 이동했다. 그 페이지는 글 목록만 나열하는 화면이었다. 딱히 의미 있는 정보가 없었다.

    해결 방법은 단순했다. 링크를 그냥 껐다. 상단 작성자 표시와 하단 저자 소개 박스, 둘 다 이름에 걸린 링크를 제거했다.

    대신 저자 소개 박스 아래에 ‘소개 보기 →’ 링크를 달았다. /about/ 페이지로 연결된다. 소개가 필요하면 거길 누르면 된다. 저자 박스 구성은 프로필 사진, 이름 ‘JIN’, 짧은 소개 문구, 그리고 그 링크다.

    예전 ‘← 이전 글’ 내비게이션은 지금 읽는 글과 관련 없는 글로 넘어가는 경우가 많아서 클릭할 이유가 없었다. 그 자리를 저자 소개 박스가 대신한다.

    글 하단 저자 소개 박스와 '함께 보면 좋은 글' 카드 섹션 — 댓글창과 이전 글 내비게이션이 있던 자리를 대체한 실제 화면

    위가 완성된 하단 모습이다. 저자 소개 박스 아래로 관련 글 카드 3개가 이어진다. 현재 글 자신은 카드에 안 나온다.

    모바일에서 제목이 이상하게 줄바꿈되는 문제를 CSS로 간단히 고치기

    홈페이지 상단 제목이 원래 ‘블로그’라고만 적혀 있었다. 무슨 블로그인지 설명이 전혀 없었다. ‘Claude Code 실전 자동화 기록’으로 바꿨다.

    홈페이지 데스크톱 화면 ,  '블로그'였던 제목을 'Claude Code 실전 자동화 기록'으로 바꾼 모습

    위가 바뀐 홈 제목의 데스크톱 화면이다.

    제목이 길어지면서 문제가 생겼다. 모바일 화면에서 단어 중간이 잘려서 줄바꿈됐다. 예를 들면 ‘자동화’가 ‘자동’과 ‘화’로 나뉘어서 두 줄에 걸쳐 나오는 식이다. 보기 나빴다.

    처음엔 단어 사이마다 줄바꿈 방지 공백( )을 일일이 넣었다. 동작은 했지만 코드가 지저분했다. 그리고 제목이 바뀔 때마다 또 넣어야 하는 구조였다.

    CSS(Cascading Style Sheets, 웹페이지의 디자인과 레이아웃을 담당하는 언어) 속성 하나로 해결했다.

    • word-break: keep-all , 단어 단위로만 줄바꿈되게 하는 속성이다. 한국어, 중국어, 일본어에 효과적이다.

    속성 하나 추가했더니 공백을 일일이 넣은 코드가 전부 필요 없어졌다. 훨씬 깔끔하다.

    word-break: keep-all 적용 후 모바일 화면 ,  제목이 단어 단위로 자연스럽게 줄바꿈된다

    위는 word-break: keep-all 적용 후 모바일 화면이다. 단어가 잘리지 않고 자연스럽게 줄바꿈된다.

    이번 작업에서 가장 번거로웠던 건 매번 캐시를 지워야 변경이 반영된다는 점이었다. 코드는 올라갔는데 화면이 안 바뀌어서 잠깐 당황한 적도 있었다. 다음엔 REST API 작업 외에 홈 페이지 레이아웃 전체를 손볼 생각이다.

  • 워드프레스 SEO 플러그인 충돌 피하는 법, 켜야 할 것과 꺼야 할 것

    워드프레스 SEO 플러그인 충돌 피하는 법, 켜야 할 것과 꺼야 할 것

    워드프레스 새로 만들면 플러그인 목록 바로 확인하는 사람이 얼마나 될까. 나는 안 했다. 그냥 랭크매스 설치하고 활성화했다가 워드프레스 SEO 플러그인 충돌을 직접 겪었다. 그게 실수였다.

    호스팅사가 몰래 깔아주는 SEO 플러그인, 확인하는 법

    호스팅어(Hostinger)에서 워드프레스를 새로 만들면 플러그인이 이미 몇 개 깔려 있다. 기본 번들이다. 문제는 그 안에 All in One SEO가 활성화된 채로 포함돼 있다는 거다.

    처음엔 몰랐다. 랭크매스를 쓰기로 마음먹고 설치부터 했다. 설치 자체는 문제없이 됐다. 그런데 활성화하고 나서 플러그인 목록을 열어봤더니 — All in One SEO가 이미 켜져 있었다. 두 개가 동시에 활성 상태였다.

    확인 방법은 간단하다. 워드프레스 관리자 화면에서 플러그인 → 설치된 플러그인으로 들어간다. 목록 상단에 ‘전체 | 활성 | 비활성’ 탭이 보인다. 활성 탭을 클릭해서 지금 켜진 플러그인만 따로 보는 게 제일 확실하다. 전체 목록에서 눈으로 훑는 건 놓치기 쉽다.

    워드프레스 새로 설치할 때 SEO 플러그인 충돌 피하는 법 ,  켜야 할 것, 꺼야 할 것 스크린샷 1

    위 화면처럼 활성 플러그인 목록을 확인하면 워드프레스 SEO 플러그인 충돌 여부를 바로 알 수 있다. 자세한 확인 방법은 워드프레스 공식 플러그인 관리 문서에도 나온다. 여기서 두 개 이상 보이면 즉시 하나를 꺼야 한다.

    호스팅어뿐 아니라 다른 호스팅사도 비슷하게 기본 플러그인을 깔아두는 경우가 있다. 새 워드프레스를 만들었다면 플러그인 목록 확인이 첫 번째 할 일이다.

    SEO 플러그인을 두 개 켜면 안 되는 이유 (메타박스, 스키마 마크업 충돌)

    워드프레스 SEO 플러그인 충돌이 실제로 왜 문제인지 구체적으로 알아야 경각심이 생긴다.

    첫 번째 문제는 메타박스(Meta Box, 글 편집 화면 아래쪽에 뜨는 SEO 입력 칸) 중복이다. 글을 쓰다 보면 편집 화면 아래에 SEO 제목, 설명, 키워드를 입력하는 칸이 뜬다. SEO 플러그인이 두 개면 이 칸이 두 세트가 된다. 어느 쪽 설정이 실제로 적용되는지 알 수 없다. 헷갈린다. 별로다.

    두 번째 문제가 더 심각하다. 스키마 마크업(Schema Markup, 구글이 검색 결과에 별점·날짜 같은 정보를 표시할 때 읽는 구조화 데이터) 충돌이다. 두 플러그인이 각자 스키마 마크업을 만들어낸다. 구글 입장에서는 같은 페이지에 두 개의 서로 다른 구조 데이터가 존재하는 셈이다. 어느 걸 믿어야 할지 모른다. 검색 엔진 최적화(SEO)가 목적인데 오히려 역효과다.

    워드프레스 SEO 플러그인 충돌을 막으려면 SEO 플러그인은 하나만 켜야 한다. 예외는 없다.

    All in One SEO 비활성화할 때 자주 실패하는 이유

    비활성화 버튼을 눌렀다. 그런데 안 꺼졌다. 이건 좀 웃겼다.

    나중에 이유를 알았다. All in One SEO를 비활성화하려고 버튼을 클릭한 순간, 화면에 설문 팝업이 떴다. 플러그인을 끄기 전에 이유를 물어보는 팝업이다. 그 팝업이 클릭을 가로채고 있었던 거다. 버튼을 눌렀다고 생각했는데 팝업 영역을 누른 셈이었다.

    팝업이 떠 있으면 반드시 팝업을 먼저 처리해야 한다. 닫든 제출하든 상관없다. 그다음에 비활성화 버튼을 다시 눌러야 실제로 꺼진다.

    비활성화 후 확인도 직접 해야 한다. 플러그인 목록 상단에 이런 식으로 표시된다.

    • 전체 (13) | 활성 (9) | 비활성 (4)

    비활성화 전후로 활성 숫자가 하나 줄었는지 확인하는 게 제일 확실하다. 숫자가 안 줄었으면 비활성화가 실제로 안 된 거다. 다시 해야 한다.

    워드프레스 새로 설치할 때 SEO 플러그인 충돌 피하는 법 ,  켜야 할 것, 꺼야 할 것 스크린샷 2

    비활성화가 제대로 됐으면 플러그인 목록에서 이 플러그인의 링크가 ‘비활성화’가 아니라 ‘활성화’로 바뀌어 있다. 위 화면이 그 상태다 , All in One SEO 옆에 ‘활성화’ 링크가 뜬다는 건 지금 꺼져 있다는 뜻이다.

    호스팅어 기본 플러그인 중 뭘 켜두고 뭘 꺼야 할까?

    호스팅어 기본 번들 플러그인을 전부 쓸 필요는 없다. 실제로 정리해봤다.

    플러그인 이름 처리 이유
    All in One SEO 비활성화 랭크매스를 메인으로 쓰므로 충돌 방지를 위해 꺼야 함
    Hostinger Reach 비활성화 SEO·콘텐츠 작업에 불필요
    Hostinger Tools 비활성화 SEO·콘텐츠 작업에 불필요
    호스팅어 간편한 온보딩 비활성화 초기 설정 이후 불필요
    LiteSpeed Cache 유지 캐시(Cache, 페이지를 미리 저장해 속도를 높이는 기능)로 사이트 속도 향상에 기여
    Site Kit by Google 유지 구글 서치콘솔·애널리틱스 연동에 계속 필요

    정리하면 호스팅어 번들 중 실제로 쓸 것은 LiteSpeed Cache와 Site Kit by Google 두 개다. 나머지는 꺼도 된다.

    충돌 없이 안전하게 설치해도 되는 플러그인 5가지

    SEO 플러그인처럼 서로 충돌하는 플러그인이 있는 반면, 그냥 설치하면 되는 것들도 있다. 직접 설치해서 쓰고 있는 5개다.

    • WP File Manager (비트 파일 관리자) , 워드프레스 관리자 화면에서 직접 서버 파일을 관리할 수 있다. FTP(File Transfer Protocol, 파일을 서버에 올리고 내리는 프로토콜) 없이도 파일을 수정할 수 있어서 편하다.
    • Converter for Media , 업로드하는 이미지를 WebP(웹피, 구글이 만든 이미지 형식으로 용량이 작아 로딩이 빠름) 형식으로 자동 변환해준다. 따로 손댈 게 없다.
    • Head & Footer Code , 헤더와 푸터에 직접 코드를 삽입할 수 있다. 구글 태그 같은 걸 넣을 때 쓴다.
    • Instant Indexing , 글을 발행하면 구글에 즉시 색인 요청을 자동으로 보내준다.
    • 럭키WP 목차 , 글 안에 목차를 자동으로 만들어준다. 긴 글일수록 유용하다.

    이 5개는 SEO 플러그인처럼 같은 기능을 두 개가 동시에 담당하는 구조가 아니다. 설치하고 활성화하면 된다.

    플러그인 활성화 후 반드시 해야 할 확인 작업

    플러그인 설치하고 활성화했다고 끝이 아니다. 확인이 남아 있다.

    워드프레스 새로 설치할 때 SEO 플러그인 충돌 피하는 법 ,  켜야 할 것, 꺼야 할 것 스크린샷 3

    반대로 랭크매스는 옆에 ‘비활성화’ 링크가 뜬다 , 이건 지금 켜져 있다는 뜻이다. 이렇게 SEO 플러그인 중 딱 하나만 ‘비활성화’ 링크가 보이는 상태가 맞는 상태다.

    확인 순서는 이렇다.

    • 활성 탭을 클릭해서 현재 켜진 플러그인 목록만 본다.
    • SEO 플러그인이 하나인지 반드시 확인한다. 두 개 이상이면 하나를 당장 꺼야 한다.
    • 비활성화한 플러그인은 비활성 탭에서 숫자가 늘었는지 확인한다.
    • 새로 설치한 플러그인이 활성 탭에 정상 표시되는지 본다.

    이걸 한 번만 제대로 해두면 나중에 ‘왜 SEO 설정이 안 먹히지?’ 같은 상황을 방지할 수 있다.

    워드프레스 SEO 플러그인 충돌 문제를 해결했으니 이제 랭크매스 초기 설정을 해야 한다. 설치만 하면 자동으로 최적화되는 게 아니다. 랭크매스 설정 마법사에서 직접 사이트 정보를 입력해야 제대로 작동한다. 포커스 키워드가 REST로 안 먹힐 때 직접 넣는 방법은 이전 글에 정리해뒀다.

    같은 워드프레스 주제로 이어서 읽으면 좋은 글: WPCode로 보안 헤더 추가하다 코드가 깨진 이유, 대표 이미지가 잘리는 이유 , 템플릿 비율 3:2→16:9 차이, 워드프레스 SEO 버그 5개, curl로 찾은 공통 원인.

  • 랭크매스 포커스 키워드, wp.data로 직접 넣는 법

    랭크매스 포커스 키워드, wp.data로 직접 넣는 법

    ujinify.com 업로드 스크립트가 REST API(Application Programming Interface, 외부에서 워드프레스 데이터를 주고받는 통로)로 랭크매스 포커스 키워드를 보내고 있었다. 응답도 200이 왔다. 에러도 없었다. 그런데 글을 열어보면 포커스 키워드 칸이 비어 있다.

    조용히 무시당한 거다. 한동안 이걸 몰랐고, 그동안은 글마다 에디터를 열어서 손으로 키워드를 입력했다. 글이 늘수록 이게 제일 귀찮은 수작업이었다.

    이 글은 그 문제를 해결한 방법을 정리한다. wp.data라는 워드프레스 내부 저장소(앱 안에서 데이터를 관리하는 공간)를 직접 건드리는 방식이다.

    REST API가 랭크매스 포커스 키워드를 무시하는 이유

    REST API로 글을 저장할 때 meta 필드에 rank_math_focus_keyword를 넣으면 된다고 생각했다. 실제로 그렇게 했다. 그리고 저장은 됐다. 응답 코드도 200이었다.

    랭크매스가 이 값을 받아도 포커스 키워드로 반영하지 않는다. 에러를 주지도 않는다. 그냥 없는 것처럼 동작한다.

    정확한 내부 원인까지는 확인하지 못했다. 확인한 건 하나다. 랭크매스의 점수 계산 엔진(SEO 점수를 계산하는 프로그램)이 브라우저 자바스크립트(JavaScript, 웹 브라우저에서 실행되는 프로그래밍 언어)로 돌아가서, 에디터 화면을 열었을 때만 점수가 계산된다. 키워드도 그 화면 안에서 넣으면 들어갔다.

    스크립트가 이걸 감지해서 경고는 띄워주게 됐지만, 근본 해결은 아니었다. 에디터를 열고 직접 넣는 수밖에 없었다. 그러다 자동화할 방법을 찾기 시작했다.

    wp.data 저장소에서 랭크매스 액션 찾기

    wp-admin(워드프레스 관리자 화면) 글 에디터를 열어둔 상태에서 시작했다.

    이 글의 코드는 브라우저 개발자 도구 콘솔(Console, 코드를 직접 실행할 수 있는 창)에 그대로 붙여 넣어도 돌아가는 코드다. 나는 같은 코드를 Playwright(브라우저 자동 조종 도구)로 실행했다. 워드프레스 블록 에디터는 wp.data라는 내부 저장소 시스템을 쓴다. 워드프레스 공식 문서에도 나오는 방식이다. 플러그인도 여기에 자기 저장소를 등록할 수 있다. 랭크매스도 그렇게 했다.

    콘솔에 이렇게 입력하면 랭크매스 저장소에 접근할 수 있다.

    wp.data.select('rank-math')

    그리고 액션(Action, 저장소에 변경을 가하는 명령)을 확인하려면 이렇게 입력한다.

    wp.data.dispatch('rank-math')

    여기서 액션이 87개나 나왔다. 이름을 하나씩 보다가 바로 눈에 띄는 게 있었다. updateKeywords, updateDescription, updateSerpDescription, updateTitle. 이름만 봐도 뭘 하는지 명확했다.

    아래 스크린샷은 이 방식으로 값을 넣은 글의 에디터 화면이다. 오른쪽 랭크매스 패널에 포커스 키워드와 점수(78/100)가 들어가 있다.

    랭크매스 포커스 키워드가 REST로 안 들어갈 때, wp.data로 직접 넣는 법 스크린샷 1

    액션 이름은 랭크매스 버전에 따라 바뀔 수 있다. 지금 여기서 나열하는 이름들은 현재 ujinify.com에 설치된 랭크매스에서 직접 확인한 것들이다. 버전이 다르면 이름이 달라질 수 있으니 반드시 직접 확인해야 한다.

    updateKeywords로 포커스 키워드 직접 입력하기

    확인했으니 바로 써봤다. 콘솔에서 이렇게 입력했다.

    wp.data.dispatch('rank-math').updateKeywords('세션 ID')

    포커스 키워드 칸에 바로 들어갔다. 4초쯤 기다렸더니 랭크매스 점수가 22점에서 71점으로 뛰었다.

    이게 맞는 방법이었다. REST API를 우회해서 에디터가 직접 받아서 처리하는 경로로 넣는 거다.

    저장까지 마치려면 core/editor(워드프레스 에디터의 핵심 저장소)의 savePost()를 써야 한다. 비동기 함수라서 await를 붙여서 호출했다.

    await wp.data.dispatch('core/editor').savePost()

    내가 쓴 순서는 이렇다. updateKeywords를 먼저 호출하고, 점수 갱신을 잠깐 기다린 뒤, savePost()로 저장했다.

    updateDescription, updateTitle로 다른 메타데이터 채우기

    포커스 키워드만 넣었는데 점수가 71점이었다. 메타 설명(검색 결과에 표시되는 글 요약문)이 비어 있었다.

    updateDescription으로 메타 설명을 넣었더니 73점이 됐다.

    wp.data.dispatch('rank-math').updateDescription('여기에 메타 설명 텍스트를 넣는다')

    같은 방식으로 SEO 제목도 바꿀 수 있다.

    wp.data.dispatch('rank-math').updateTitle('여기에 SEO 제목을 넣는다')

    updateSerpDescription도 있었는데, SERP에 표시되는 설명을 따로 관리하는 액션이다. 저장소에 이름이 있으니 확인해두면 된다.

    이후 본문 첫 10% 안에 키워드가 없다는 항목이 걸려 있어서 첫 문단에 문장을 하나 추가했다. 긴 문단을 쪼개고, 제목이 키워드로 시작하게 순서를 바꿨다. 첫 번째 글은 최종 76점까지 올라갔다. 두 번째 글은 70점에서 시작해서 본문에 실제 캡처 이미지 2장을 추가했더니 78점이 됐다.

    아래 스크린샷은 랭크매스 패널의 항목 목록이다. 통과 항목은 초록, 감점 항목은 빨강이다. URL 항목이 빨간색으로 남아 있다.

    랭크매스 포커스 키워드가 REST로 안 들어갈 때, wp.data로 직접 넣는 법 스크린샷 2

    점수 갱신이 늦거나 예전 값이 나올 때 확인법

    헷갈리는 지점이 있었다. window.rankMathEditor.resultManager.getResults()로 테스트 통과 여부를 읽었는데, 키워드가 제목에도 본문에도 분명히 있는데 전부 false로 나왔다.

    화면 항목 목록에는 ‘제목에 포커스 키워드를 사용하고 있습니다’가 통과로 표시돼 있었다. 이 값은 갱신이 늦거나 예전 스냅샷(특정 시점의 데이터 복사본)을 돌려주는 거였다. 그래서 getResults() 반환값은 신뢰하지 않기로 했다. 화면에 보이는 항목 목록을 기준으로 삼는다.

    또 하나. 통과(has: true)로 표시돼도 점수가 다 들어오지 않는 항목이 있다. 이미지 항목은 1/6점, 본문 길이는 2/8점처럼 부분 점수로 처리되는 경우가 있었다. 점수가 기대보다 낮게 나오면 이걸 먼저 확인해야 한다. 통과 여부만 보고 끝내면 안 된다.

    화면에 뜬 점수와 데이터베이스에 저장된 점수가 다를 수도 있다. 저장 후에는 REST API로 get-post-seo-meta를 조회해서 DB에 실제로 반영된 점수를 따로 확인해야 한다. 이 단계를 빼면 안 된다. 화면 숫자만 믿다가 나중에 데이터가 다른 걸 발견하면 그때는 더 번거롭다.

    이 방법의 한계와 실제 적용 시 주의점

    이 방법에는 명확한 한계가 있다. 숨기지 않겠다.

    • 브라우저 에디터를 열어야 한다. REST API나 MCP(Model Context Protocol, AI 도구가 외부 서비스에 명령을 보내는 통신 방식)만으로는 동작하지 않는다. 점수 계산 엔진이 브라우저 자바스크립트라서, 에디터 화면이 열려 있어야 실행된다.
    • 액션 이름이 버전마다 다를 수 있다. updateKeywords, updateDescription 같은 이름은 현재 내 사이트 랭크매스에서 직접 확인한 것들이다. 업데이트 후에 이름이 바뀌면 동작하지 않는다. 사용 전에 반드시 wp.data.dispatch('rank-math')를 콘솔에서 직접 실행해서 목록을 확인해라.
    • 저장 후 DB 값을 반드시 확인해야 한다. 화면 점수와 실제 DB에 저장된 점수가 다를 수 있다. REST API로 get-post-seo-meta를 조회하는 단계를 절대 생략하지 마라.
    • 올릴 수 없는 점수가 존재한다. URL에 한국어 키워드가 없는 항목(5점), 유료 Content AI 항목(5점)은 구조적으로 올리기 어렵거나 올리지 않을 항목이다. 이 점수를 제외하면 실제 달성 가능한 최대치는 처음부터 그만큼 낮다.

    수작업으로 키워드를 하나씩 입력하는 것보다는 낫다. 하지만 완전 자동화는 아니다. 에디터 화면을 열고 콘솔에서 코드를 실행하는 단계는 여전히 남는다.

    지금은 이 정도로 쓰고 있다.

    랭크매스 점수가 왜 에디터를 열어야 계산되는지는 랭크매스 SEO 16점→76점 글에, 같은 결의 버그 다섯 개는 워드프레스 SEO 버그 5개 총정리에 정리해뒀다.

    같은 랭크매스 주제로 이어서 읽으면 좋은 글: 랭크매스 무료 기능으로 고아 포스트 2개 찾아낸 이야기, 메타 설명 오류 — 색인됐는데 검색 안 되던 이유.

  • 세션 ID 문제, Claude Code에서 MCP가 안 보이는 이유

    세션 ID 문제, Claude Code에서 MCP가 안 보이는 이유

    ujinify.com 워드프레스에 MCP Adapter가 코어에 내장돼 있다는 걸 알게 됐다. 나중에 밝혀졌지만, 이 이야기의 결론은 결국 세션 ID 하나였다.

    거기에 랭크매스(워드프레스 SEO 플러그인)가 ability(어빌리티, 서버가 외부에 제공하는 기능 단위)를 25개나 등록해뒀다. get-seo-scores로 여러 글 점수를 한 번에 조회하거나, audit-site-seo/fix-site-seo로 사이트 전체를 진단하고 자동 수정하거나, set-homepage-seo로 설정까지 바꿀 수 있는 것들이었다.

    그전까지는 SEO 점수 하나 확인하려면 Playwright(플레이라이트, 브라우저를 자동으로 조종하는 도구)로 wp-admin 에디터를 직접 열어야 했다. 이걸 Claude Code에 MCP 서버로 등록하면 API 호출 하나로 끝낼 수 있겠다 싶었다. 그래서 등록했다. 그리고 아무것도 안 됐다.

    문제: MCP가 ‘연결됨’인데 tool이 하나도 안 보여요

    등록 자체는 간단했다.

    claude mcp add --transport http ujinify-wp <MCP 서버 URL> --header "Authorization: Basic ..."

    claude mcp list를 돌리면 “✔ Connected”가 떴다. 연결됐다는 뜻이다. 그런데 ToolSearch(툴서치, Claude Code에서 사용 가능한 도구를 찾는 기능)로 아무리 찾아봐도 랭크매스 tool(툴, 도구)이 하나도 잡히지 않았다. 매번 “No matching deferred tools found”였다. 세션을 새로 시작해봤다. 재시작도 해봤다. 결과는 똑같았다.

    서버는 연결됐다는데, 실제로 쓸 수 있는 tool은 하나도 없는 상태. 이건 좀 웃겼다.

    curl로 직접 테스트해보니 세션 ID가 필요했다

    Claude Code를 믿지 않기로 했다. curl(컬, 터미널에서 HTTP 요청을 직접 보내는 도구)로 MCP 서버에 직접 말을 걸어보기로 했다.

    먼저 initialize(초기화 요청, MCP 서버와 처음 악수하는 단계)를 호출했다. 서버는 정상 응답했다. 그런데 응답 헤더(header, 서버가 응답과 함께 보내는 부가 정보)를 보니 mcp-session-id라는 값이 딸려 내려왔다. 이 서버는 Streamable HTTP(스트리머블 HTTP, 요청마다 세션 ID를 주고받는 MCP 통신 방식)를 쓰는 타입이었다.

    그 상태에서 세션 ID 없이 바로 tools/list를 호출했다. 결과는 “Missing Mcp-Session-Id header” 에러였다. 반대로, initialize에서 받은 세션 ID를 Mcp-Session-Id 헤더에 실어서 tools/list를 다시 호출했더니 — 랭크매스가 등록한 tool 3개의 스키마(schema, 도구의 구조와 사용법을 정의한 명세)가 정상으로 내려왔다.

    서버는 100% 정상이었다. 문제는 Claude Code 쪽이었다.

    왜 Claude Code는 세션 ID를 못 챙겼을까

    MCP 통신은 핸드셰이크(handshake, 통신 시작 전에 서로 규칙을 맞추는 절차)가 필요하다. MCP 공식 스펙 문서에도 명시돼 있는 내용인데, 순서는 이렇다.

    • initialize 요청을 보낸다.
    • 서버가 응답 헤더로 세션 ID를 내려준다.
    • 이후 모든 요청에 그 세션 ID를 Mcp-Session-Id 헤더에 실어서 보낸다.

    Claude Code의 HTTP MCP 클라이언트가 이 두 번째와 세 번째 단계를 처리하지 못하고 있었다. initialize는 성공했지만, 거기서 받은 세션 ID를 이후 요청에 다시 실어 보내지 않는 것이다.

    claude mcp list의 “Connected” 표시는 initialize 성공만 확인한다. 그러니 이 핸드셰이크 실패를 잡아내지 못하고, 겉으로는 정상처럼 보인다. 연결은 됐지만 실제로 아무것도 못 쓰는 상태가 “Connected”로 표시되는 것이다. 별로였다.

    해결책: 직접 만든 함수로 세션 핸드셰이크 처리하기

    MCP tool 등록에 기대는 걸 포기했다. 대신 이 핸드셰이크 절차를 그대로 코드로 옮겼다.

    scripts/rankmath-mcp.ts에 callRankMathAbility 함수를 만들었다. 이 함수는 호출될 때마다 아래 순서를 자동으로 처리한다.

    • initialize 요청을 보내서 세션 ID를 받는다.
    • 받은 세션 ID를 헤더에 실어서 tools/call을 호출한다.
    • 결과를 반환한다.

    CLI(커맨드 라인 인터페이스, 터미널에서 명령어로 프로그램을 실행하는 방식)에서 바로 쓸 수 있게 npm run rankmath -- <ability-name> '<json-params>' 형태로도 만들었다. 기존 upload.ts의 getWpConfig()를 그대로 재사용해서 인증 정보를 따로 관리할 필요도 없게 했다.

    Claude Code가 못 하는 걸 직접 구현한 것이다. 우아하진 않지만 동작한다.

    실제로 점수를 가져왔을 때 검증 결과

    get-seo-scores ability(어빌리티, 여기서는 랭크매스가 MCP를 통해 제공하는 기능)를 호출해서 여러 글의 점수를 한 번에 받아봤다. 이전에 Playwright로 wp-admin 에디터를 직접 열어서 확인했던 점수와 정확히 일치했다. 132번 글 81점, 109번 글 83점, 42번 글 79점. 숫자가 맞았다.

    그다음엔 실제로 사이트 전체를 점검했다. seo_filter를 bad(50점 이하), empty-fk(포커스 키워드 없음), unscored(채점 안 됨)로 각각 돌렸다. 결과는 깔끔했다. 문제되는 글은 하나도 없었다. 포커스 키워드가 없는 건 애초에 필요 없는 고정 페이지 3개뿐이었다.

    브라우저를 한 번도 열지 않았다. 몇 초 만에 끝났다.

    이 방법의 한계, 읽기만 되고 쓰기는 안 된다

    명확히 해둬야 할 게 있다.

    get-seo-scores는 데이터베이스에 이미 저장된 점수를 ‘읽기’만 한다. 랭크매스의 점수 계산 엔진 자체는 여전히 브라우저, 구체적으로는 wp-admin 에디터의 자바스크립트에서만 돌아간다. 새 글을 올리거나 콘텐츠를 수정한 직후에 점수를 새로 계산하려면 여전히 에디터를 열어야 한다. REST나 MCP로는 재계산을 트리거할 방법이 없다.

    analyze-post-content라는 ability도 있다. 이건 점수를 주지 않는다. 원본 콘텐츠와 24개 테스트 목록, 채점 기준 문서를 던져주고 AI가 직접 채점하라는 방식이다. 손이 많이 가서 아직 시도하지 않았다.

    결국 이 방법으로 해결된 건 ‘이미 채점된 점수를 빠르게 읽는 것’이다. 채점 자체는 여전히 브라우저 의존이다. 한계를 알고 쓰면 된다. 모르고 쓰면 나중에 헷갈린다.

    다음에는 analyze-post-content를 실제로 써볼 생각이다. AI가 직접 채점한 결과가 랭크매스 공식 점수와 얼마나 차이 나는지 비교해보면 쓸만한지 아닌지 판단할 수 있을 것이다.

    “설정 화면에 값이 있다고 실제로 작동한다는 보장은 없다”는 패턴은 이번에도 반복됐다. 워드프레스 SEO 버그 5개 총정리 글에서 다룬 다섯 가지 사례와 정확히 같은 결이다. 이번엔 랭크매스 설정이 아니라 Claude Code의 MCP 연결 상태였다는 것만 다르다.

    세션 쪽에서 겪은 또 다른 문제는 Claude 5시간 한도 72% 찍힌 이유는 세션 길이였다에도 있다.

  • 워드프레스 SEO 버그 5개, curl로 찾은 공통 원인

    워드프레스 SEO 버그 5개, curl로 찾은 공통 원인

    블로그에 글이 15개쯤 쌓였을 때 돌아봤다. 그중 5개가 전부 워드프레스 SEO 설정을 자동화하거나 고치다가 만난 버그 이야기였다. 흩어져 있으니까 불편했다. 나중에 비슷한 문제를 다시 만났을 때 어느 글을 찾아야 할지 헷갈렸다. 그래서 한 페이지에 몰아서 정리하기로 했다.

    설정을 저장했는데도 작동하지 않은 이유

    다섯 개를 나란히 놓고 보니까 패턴이 보였다. 전부 같은 이야기였다.

    ‘설정 화면에 값이 있다고 해서 실제로 그게 적용되고 있다는 보장은 없다.’

    WPCode에서는 코드를 저장했는데 실제로는 깨진 채로 배포됐다. 랭크매스에서는 홈페이지 메타 설명을 입력해도 워드프레스 읽기 설정 때문에 그 값이 조용히 무시됐다. REST API(워드프레스에 데이터를 보내고 받는 통로)로 포커스 키워드를 보내도 저장이 안 되는 경우도 여러 번 있었다.

    관리자 화면의 저장 성공 메시지, REST API의 200 응답, 설정 페이지에 입력된 값. 이런 것들은 전부 ‘내가 뭔가를 입력했다’는 증거일 뿐이다. ‘그게 실제로 작동하고 있다’는 증거가 아니다.

    아래 다섯 개가 그 증거다.

    버그 1: 랭크매스 점수가 재계산되지 않는 이유 (16점→76점의 함정)

    랭크매스(워드프레스용 SEO 플러그인)가 매기는 SEO 점수가 16점이었다. 뭘 고쳐야 할지 몰랐다. 점수만 보면 아무것도 알 수 없었다.

    처음에는 REST API로 점수를 강제로 재계산시키려고 했다. 여기서 함정에 빠질 뻔했다. API 응답은 200으로 떴다. 성공처럼 보였다. 그런데 실제 점수는 그대로였다.

    원인은 단순했다. 랭크매스 SEO 점수는 wp-admin(워드프레스 관리자 에디터 화면)을 직접 열어야 제대로 계산된다. API로 우회하면 점수가 갱신되지 않는다. 에디터를 열고 나서야 점수가 76점으로 올라갔다.

    이 경험에서 배운 것은 하나다. API 응답이 성공이어도 실제 결과를 화면에서 직접 확인해야 한다. 200은 ‘요청이 도착했다’는 뜻이지 ‘원하는 대로 됐다’는 뜻이 아니다.

    → 전체 진단 과정: 랭크매스 SEO 16점→76점, API 함정 피하고 올린 과정

    버그 2: WPCode 보안 헤더가 깨지는 현상 (저장은 됐는데 적용 안 됨)

    WPCode(워드프레스에 코드 조각을 추가하는 플러그인)로 보안 헤더(Security Header, 브라우저에 보안 정책을 전달하는 HTTP 응답값)를 추가했다. PHP 코드 스니펫(snippet, 짧은 코드 조각)을 넣고 저장했다. 저장 성공 메시지가 떴다.

    그런데 실제로는 헤더가 적용되지 않고 있었다.

    curl(터미널에서 웹 페이지 응답을 직접 확인하는 명령어)로 라이브 페이지 응답 헤더를 확인하고 나서야 알았다. 보안 헤더가 없었다. 원인은 사소한 문법 오류였다. PHP 코드 안에 오타가 있었고, 그 오류 때문에 코드 전체가 실행되지 않았다.

    저장 성공 메시지만 보고 넘어갔으면 계속 몰랐을 거다. WPCode는 코드 내용의 오류를 검증하지 않는다. 저장 자체는 항상 성공한다. 그래서 더 위험하다.

    보안 설정을 추가한 뒤에는 반드시 curl로 응답 헤더를 직접 확인해야 한다. 저장 성공 메시지를 믿지 마라.

    curl -I https://내-사이트-주소.com

    위 명령어를 터미널에 입력하면 응답 헤더 목록이 나온다. 추가한 헤더 이름이 거기 있어야 진짜 적용된 거다.

    → 전체 진단 과정: WPCode로 보안 헤더 추가하다 코드가 깨진 이유

    버그 3~4: fire-your-seo-agency와 AI Link Genius로 만난 예상 밖의 문제들

    fire-your-seo-agency는 Claude Code에서 쓸 수 있는 스킬(skill, AI에게 특정 작업 방식을 지정하는 설정)이다. 이걸로 블로그 4개를 한꺼번에 SEO 점검했다.

    중간에 파일이 세 번 중복으로 받아지는 해프닝이 있었다. 이건 좀 웃겼다. 그래도 생각보다 빠르게 끝났다. 스킬 하나로 블로그 4개를 동시에 점검한다는 게 실제로 되는 일이라는 걸 이때 처음 확인했다.

    → 전체 진단 과정: fire-your-seo-agency 스킬로 4개 블로그 자동 SEO 최적화한 후기

    네 번째 버그는 AI Link Genius 이야기다. AI Link Genius는 랭크매스 안에 있는 내부 링크 분석 기능이다. 설치는 해놨는데 한 번도 안 써봤다. 어느 날 다시 살펴보다가 고아 포스트(Orphan Post, 다른 글에서 링크를 하나도 받지 못한 글)가 2개 있다는 걸 발견했다.

    그 글들은 검색 엔진이 찾아오기 어려운 상태였다. 내부 링크를 걸어주고 나서야 제대로 연결됐다.

    → 전체 진단 과정: 랭크매스 무료 기능으로 고아 포스트 2개 찾아낸 이야기

    이 두 버그에서 공통으로 배운 게 있다. 설치는 해놨지만 한 번도 안 써본 플러그인 기능이 있는지 주기적으로 점검해야 한다. 있는 기능을 모르고 있으면 없는 거나 마찬가지다.

    버그 5: 메타 설명이 검색엔진에 반영 안 되는 이유 (읽기 설정의 함정)

    홈페이지가 색인됐는데 메타 설명이 이상했다. 랭크매스에 분명히 입력해뒀는데, 검색 결과에 다른 문구가 나왔다.

    ‘색인 = 노출’이라고 착각하고 있었다. 아니었다. 색인됐어도 메타 설명이 틀리면 검색 결과가 이상하게 보인다.

    원인은 워드프레스 읽기 설정이었다.

    워드프레스 관리자 화면 → 설정 → 읽기 에서 홈페이지 표시가 ‘최신 글’로 설정되어 있으면, 랭크매스에 입력한 홈페이지 메타 설명이 무시된다. 대신 워드프레스 기본 태그라인이 메타 설명 자리에 들어간다.

    랭크매스 설정 화면에는 분명히 내가 쓴 문구가 있었다. 그런데 실제 HTML에는 태그라인이 들어가 있었다. curl로 확인하기 전까지 몰랐다.

    curl -s https://내-사이트-주소.com | grep -i "meta name=\"description\""

    위 명령어로 실제 HTML에 박힌 메타 설명을 확인할 수 있다. 설정 화면에 뭐가 적혀 있든 상관없다. 이 결과가 진짜다.

    홈페이지 메타 설명을 제대로 쓰려면 읽기 설정에서 ‘정적 페이지’를 선택하고 홈페이지를 지정해야 한다. 그래야 랭크매스가 입력한 값을 실제로 가져다 쓴다.

    → 전체 진단 과정: 메타 설명 오류 — 색인됐는데 검색 안 되던 이유

    다음 버그를 빨리 찾는 4가지 확인 순서 (curl 포함)

    다섯 번을 겪고 나서 확인 순서가 생겼다. 비슷한 문제를 만나면 이 순서로 본다.

    • 첫째, 설정을 저장한 뒤 바로 curl로 라이브 페이지를 확인한다. 저장 성공 메시지는 신뢰하지 않는다. curl -s 주소 | grep 확인할내용 으로 실제 HTML에 반영됐는지 바로 본다.
    • 둘째, REST API 응답이 200이어도 응답 바디를 다시 읽는다. 200은 요청이 도착했다는 뜻이다. 원하는 처리가 됐다는 뜻이 아니다. 응답 안에 실제로 뭐가 담겨 있는지 확인해야 한다.
    • 셋째, 설정 화면 말고 ‘진짜 소스’가 따로 있는지 의심한다. 워드프레스는 표면 설정 화면 뒤에 그 값을 실제로 가져다 쓰는 다른 설정이 있을 수 있다. 읽기 설정과 태그라인이 그 예다. 플러그인 설정만 보면 안 된다.
    • 넷째, 설치는 해놨지만 한 번도 안 써본 플러그인 기능을 주기적으로 점검한다. AI Link Genius처럼, 있는 기능인지 모르고 넘어간 것들이 반드시 있다.

    이 네 가지는 순서대로 해야 빠르다. 첫째를 건너뛰고 셋째부터 보다가 시간을 날린 적이 있다. 순서를 지켜라.

    지금은 5개지만, 앞으로 비슷한 버그를 만날 때마다 이 글에 추가할 생각이다. 워드프레스 SEO 설정을 직접 만지다가 막히는 사람에게 이 페이지가 첫 번째 참고 지점이 됐으면 한다. 경험이 쌓일수록 이 목록도 길어질 거다.

    같은 워드프레스 주제로 이어서 읽으면 좋은 글: 대표 이미지가 잘리는 이유 , 템플릿 비율 3:2→16:9 차이, 이미지가 삐져나가는 버그, 원인 찾고 자동화까지 한 후기, 워드프레스 SEO 플러그인 충돌 피하기 , 켜야 할 것, 꺼야 할 것.