정신이 나가지 않게 1000개 이상의 'Levels' 페이지 이름 바꾸기

발행: (2026년 4월 21일 PM 02:02 GMT+9)
7 분 소요
원문: Dev.to

Source: Dev.to

위의 Source 링크에 있는 전체 텍스트를 제공해 주시면, 해당 내용을 한국어로 번역해 드리겠습니다.
(코드 블록, URL, 마크다운 구문 및 기술 용어는 그대로 유지됩니다.)

도전 과제

동료가 사이트에 변경 사항을 푸시한 아침에 저에게 이메일을 보냈습니다:

Hi Ice, now that we pushed the changes sa site, we need to scour the site for mentions of Level 1, Level 2, Level 1/2 and change them accordingly to
Level 1 → Intro to Neurofascial Training
Level 1/2 → Intermediate Instability Training
Level 2 → Advanced Neurofascial Training

처음 보면 간단한 찾기‑바꾸기 작업처럼 보였습니다: 워드프레스 관리자에 들어가서 검색 기능을 사용하고, 각 페이지를 수정하고, 점심 전에 끝내는 것처럼.

하지만 사이트맵을 확인해 보니 1,074 URLs가 있었습니다. “Level”이라는 단어가 포함된 페이지가 일부에 불과하더라도, 모든 글을 일일이 클릭하고, 세 가지 문자열을 각각 검색한 뒤, 어떤 교체가 적용될지 판단하는 데 최소 하루는 걸릴 것이며, 놓치는 부분이 생길 위험도 상당히 큽니다.

매핑 이름 변경

이전 텍스트새 텍스트
Level 1Intro to Neurofascial Training
Level 1/2Intermediate Instability Training
Level 2Advanced Neurofascial Training

중요한 순서 세부사항: “Level 1/2”는 “Level 1”보다 먼저 매치되어야 합니다. 단순히 교체하면 “Level 1/2”가 “Intro to Neurofascial Training/2”로 변환될 수 있습니다.

플러그인만으로는 부족한 이유

Plugins like Better Search Replace operate directly on the database. A single wrong checkbox could overwrite every “Level 1” across post content, post meta, widget text, theme options, and even places that shouldn’t be changed (e.g., analytics or audit logs).

  • No preview of where each match lives.
  • Overlapping strings mean the order of operations matters, and most plugins don’t let you sequence replacements atomically.

What I really needed was a map—a list of every occurrence with enough surrounding context to judge whether it’s safe to change, plus a direct link to the WordPress editor for that specific page. I would still perform the replacement by hand, but informed by real data.

Source:

맞춤 스캐너 만들기

나는 다음과 같은 작업을 수행하는 Python 스크립트를 작성했다.

  1. 사이트의 sitemap을 순회한다.
  2. 각 URL을 방문한다.
  3. 렌더링된 HTML에서 세 가지 패턴을 단일 정규식과 단어 경계(\b)를 사용해 검색한다.
import re

LEVEL_PATTERN = re.compile(
    r"\bLevel\s*1\s*/\s*2\b|\bLevel\s*1\b|\bLevel\s*2\b",
    re.IGNORECASE,
)

단어 경계(\b)는 “Level 10”이나 “Level 12‑week program”과 같은 잘못된 양성을 방지한다. 대체 순서는 매핑 문제를 반영한다—“Level 1/2”가 먼저 시도되므로 더 단순한 “Level 1” 패턴에 가려지지 않는다.

스크립트가 캡처하는 내용

각 매치에 대해 스크립트는 다음을 기록한다.

  • 페이지 URL
  • WordPress 포스트 ID (class에서 추출, 예: page-id-123 또는 postid-123)
  • 직접 관리자 편집 링크: /wp-admin/post.php?post=123&action=edit
  • 매치 양쪽 ≈80자 정도의 컨텍스트
  • 매치를 감싸는 HTML 태그(h2, li, p 등) – 블록 편집기에서 위치를 찾는 데 도움

모든 데이터는 CSV로 내보내고, 정렬한 뒤, 페이지 내 중복 매치는 하나로 합치며, /wp-admin/wp-json과 같은 시스템 경로는 필터링한다.

접근 방식의 장점

1,074개의 페이지를 무작위로 클릭하는 대신, 이제 “Level”이라는 단어가 어떤 형태로든 언급된 모든 페이지를 한눈에 볼 수 있는 목록을 확보했습니다. 각 항목에는 한 번의 클릭으로 편집기로 이동할 수 있는 링크와 어떤 교체가 적용될지 판단할 수 있는 충분한 컨텍스트가 제공됩니다.

컨텍스트 열이 진짜 마법입니다—예를 들어 다음과 같은 스니펫:

…우리의 대표 Level 1 수업은 매주 화요일에 진행됩니다…

이 문구는 해당 수업 이름을 **“Intro to Neurofascial Training”**으로 바꿔야 함을 명확히 보여주며, “level”이라는 단어가 단순히 사용된 경우와는 구분됩니다.

희귀한 예외 경우(역사적 텍스트, 후기 등)는 쉽게 찾아내어 건너뛸 수 있어, 무차별적인 데이터베이스 교체가 발생시킬 수 있는 오류를 방지합니다.

이 스캐너를 작성하는 데 반시간 정도만 투자했지만, 즉시 그 비용을 회수했습니다: 시간을 절약하고, 누락된 부분이 없다는 확신을 얻으며, 실수로 인한 손상을 방지하는 감사 추적을 확보했습니다.

References

  • WordPress 5.5의 새로운 XML 사이트맵 기능 — Make WordPress Core
  • 사이트맵 XML 프로토콜 — sitemaps.org
  • body_class() 함수 레퍼런스 — WordPress 개발자 리소스
  • get_body_class() 함수 레퍼런스 — WordPress 개발자 리소스
  • re — 정규 표현식 연산 — Python 3 문서
  • Better Search Replace — WordPress 플러그인 디렉터리
  • Requests: 인간을 위한 HTTP
  • Beautiful Soup 문서
0 조회
Back to Blog

관련 글

더 보기 »

다음 WordPress를 만들기 위한 경쟁

저는 article을 format하는 것을 기쁘게 도와드리겠지만, post 자체의 전체 텍스트가 필요합니다. article의 content, body text, headings 등을 제공해 주시겠어요?