Technote

개발 워크플로우 실무

연재 WP-CLI 자동화 레시피 8부 중 3부

search-replace 안전 수칙 — 직렬화와 guid

SQL 한 줄로 도메인을 바꾸면 위젯과 테마 설정이 조용히 빈 값이 됩니다. 직렬화가 문자열 길이를 함께 저장하기 때문이고, 이 문제는 도구를 바꾸는 것으로 완전히 사라집니다.

스테이징을 프로덕션에서 복제했거나, 도메인을 옮겼거나, http 에서 https 로 넘어갔다면 데이터베이스 안에 옛 주소가 잔뜩 남아 있습니다. 본문의 이미지 경로, 위젯 설정, 테마 설정, 플러그인 옵션에 흩어져 있습니다.

여기서 UPDATE … REPLACE() 한 줄이 떠오릅니다. 그 한 줄이 데이터를 깨뜨립니다. 왜인지 알면 다시는 그 유혹에 빠지지 않습니다.

왜 SQL 치환이 데이터를 깨뜨리는가

워드프레스는 배열이나 객체 형태의 설정을 직렬화된 PHP 문자열로 한 칸에 저장합니다. 그 형식은 값과 함께 문자열의 길이를 적어 둡니다.

a:1:{s:4:"logo";s:35:"https://staging.example.kr/logo.png";}
                        ↑ 뒤 문자열이 35자라는 선언

SQL 치환 후 (길이는 그대로 남는다)
a:1:{s:4:"logo";s:35:"https://example.kr/logo.png";}
                        ↑ 실제로는 27자 — 선언과 어긋난다

이 값을 unserialize() 하면 실패하고, 실패하면 get_option() 이 false 를 돌려줍니다. 화면에서는 위젯 설정 · 커스터마이저 값 · 사용자 정의 필드가 “초기화된 것처럼” 보입니다. 에러 메시지는 어디에도 없습니다. 이것이 가장 나쁜 종류의 고장입니다 — 실패가 조용하고, 원인과 증상이 멀리 떨어져 있습니다.

같은 치환이라도 직렬화를 아는 도구만 안전하다

wp search-replace 는 값을 읽어 역직렬화하고, 안쪽 문자열을 치환한 뒤, 다시 직렬화해서 씁니다. 길이는 그 과정에서 자동으로 다시 계산됩니다. 중첩된 배열 안쪽까지 따라 들어갑니다.

–dry-run 을 먼저

실행 전에 무엇이 몇 건 바뀌는지를 봅니다.

wp search-replace 'https://staging.example.kr' 'https://example.kr' --dry-run --report-changed-only

테이블별 건수가 나옵니다. 예상보다 훨씬 많다면 검색어가 너무 짧다는 신호입니다 — 도메인 없이 example 만 넣는 식의 실수가 흔합니다. 예상보다 적다면 프로토콜이 섞여 있을 수 있습니다(http:// 와 https://, www 있는 형태와 없는 형태를 각각 확인합니다).

건수가 납득되면 그때 백업입니다. wp db export before.sql 한 줄이면 되고, 이 파일이 있는지 여부가 사고의 크기를 결정합니다.

guid 는 링크가 아니라 식별자다

실무에서 쓰는 형태에는 플래그가 하나 더 붙습니다.

wp search-replace 'https://staging.example.kr' 'https://example.kr' --skip-columns=guid --report-changed-only

guid 는 주소처럼 생겼지만 주소가 아니라 영구 식별자입니다. 프론트엔드의 링크는 퍼머링크 규칙에서 만들어지고, guid 는 피드 리더가 “이 항목을 전에 본 적 있는가” 를 판단하는 데 쓰입니다.

그래서 guid 를 바꾸면 구독자의 피드에서 과거 글 전체가 새 글로 다시 뜹니다. 사이트는 멀쩡해 보이고, 문제는 남의 화면에서만 일어납니다. 워드프레스 문서가 “생성 후 절대 바꾸지 말 것” 이라고 적어 둔 값이며, 이 플래그를 습관으로 만드는 편이 낫습니다.

어느 테이블까지 볼 것인가

기본값은 워드프레스가 등록한 테이블만입니다. 플러그인이 만든 테이블은 접두사를 공유하더라도 기본 대상에 들어가지 않으므로, 필요하면 범위를 넓힙니다.

치환 범위 — 아래로 갈수록 넓고, 그만큼 되돌리기 어렵다

몇 가지 플래그를 더 알아 두면 좋습니다. --precise 는 빠른 경로 대신 항상 PHP 로 처리해 확실성을 높이고(느립니다), --export=out.sql 은 DB 를 건드리지 않고 치환된 덤프만 파일로 뽑습니다 — 이관 작업에서 특히 유용합니다. 멀티사이트에서는 --network 와 --url 을 함께 봅니다.

치환 뒤 확인

끝났다고 넘어가지 않습니다. 세 가지를 봅니다. wp option get home 과 siteurl 이 새 주소인가, 위젯과 커스터마이저 화면이 값을 그대로 갖고 있는가(직렬화가 살아 있다는 뜻입니다), 그리고 이미지가 실제로 열리는가.

브라우저 콘솔에서 혼합 콘텐츠 경고가 남아 있다면 http:// 로 시작하는 옛 경로가 아직 있다는 뜻이므로, 프로토콜만 바꾸는 치환을 한 번 더 돌립니다.

이런 이전 작업의 전체 절차는 작업 과정에 단계별로 공개돼 있고, 관련 글은 개발 워크플로우 아카이브에 있습니다.

다음 회차

명령 조합으로는 안 되는 일이 생기면 스크립트를 씁니다. 다음 회차는 eval-file 인데, 첫 5분 안에 반드시 부딪히는 벽이 하나 있습니다 — 인자 전달입니다.

이 주제의 다른 글

노하우 목록으로

개발 워크플로우 실무

캠페인 주소 관리 — 색인과 리포트가 함께 쪼개집니다

캠페인 파라미터가 붙은 주소는 검색엔진에게 별개의 주소입니다. 색인되면 같은 페이지가 여러 벌로 잡히고, 표기가 흔들리면 리포트가 쪼개집니다. 원인이 하나라 해법도 하나입니다.

마케터 5분 읽기

개발 워크플로우 심화

배포 전 디자인 QA 체크리스트

배포 후에 발견하는 디자인 문제의 대부분은 배포 전에 순서대로 확인하면 잡힙니다. 규칙 · 상태 · 실기기의 세 단계로 정리했습니다.

디자이너 3분 읽기

₩270,000 · 신청하기