명령 조합으로 해결되지 않는 일이 있습니다. 조건에 따라 갈리는 분기, 수백 건을 도는 루프, 여러 단계를 한 덩어리로 묶어야 하는 작업 같은 것들입니다. 그때 쓰는 것이 wp eval-file 입니다.
eval 과 eval-file
한 줄이면 wp eval, 파일이면 wp eval-file 입니다.
wp eval 'echo get_option( "home" );'
wp eval-file bin/report.php
둘 다 완전히 로드된 워드프레스 안에서 실행됩니다. 플러그인이 활성이고, 훅이 걸려 있고, get_posts() 도 wp_insert_post() 도 그대로 동작합니다. 부트스트랩 코드를 직접 쓸 필요가 없다는 것이 이 명령의 가치입니다.
스크립트 파일 맨 위에는 가드를 둡니다.
if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
return;
}
이 파일이 어쩌다 문서 루트 안에 놓이더라도 웹 요청으로는 아무 일도 하지 않게 됩니다. 데이터를 쓰는 스크립트라면 선택이 아닙니다.
⚠ 인자는 positional 이다
여기서 모두가 한 번 걸립니다. -- 로 시작하는 플래그는 WP-CLI 자신의 것으로 해석됩니다. 스크립트에 도착하지 않고, 모르는 플래그면 명령 자체가 거부됩니다.
# 안 된다 — --dry 는 eval-file 자신의 플래그로 먹힌다
wp eval-file bin/seed.php --dry
# 된다 — 위치 인자로 넘긴다
wp eval-file bin/seed.php dry s25
스크립트 안에서는 $args 배열로 받습니다.
$args = (array) ( $args ?? [] );
$dry = in_array( 'dry', $args, true );
이 제약은 오히려 쓸모가 있습니다. 스크립트의 인터페이스가 짧은 낱말 몇 개로 유지되기 때문입니다. 옵션이 셋을 넘어가기 시작하면 그것은 스크립트로 감당할 크기를 넘었다는 신호이고, 자체 명령으로 승격할 때입니다 — 6회차의 주제입니다.
CLI 안의 워드프레스는 웹과 다르다
같은 워드프레스지만 실행 맥락이 다릅니다. 세 가지가 특히 자주 문제를 만듭니다.
사용자 0 이 가장 멀리까지 영향을 미칩니다. 로그인한 사람이 없으므로 current_user_can() 은 전부 false 이고, 특히 unfiltered_html 이 없어서 저장할 때 콘텐츠에 kses 필터가 걸립니다. 다음 회차에서 이것이 어떤 모습으로 나타나는지 자세히 다룹니다.
훅 타이밍도 다릅니다. eval-file 은 워드프레스가 모두 로드된 뒤 실행되므로 init 같은 이른 훅은 이미 지나간 상태입니다. 스크립트 안에서 add_action( 'init', … ) 를 걸어 두고 “왜 안 돌지” 를 찾는 일이 흔한데, 늦은 것이지 틀린 것이 아닙니다 — 그 코드는 그냥 직접 호출하면 됩니다.
ABSPATH 가드에 걸려 조용히 죽는 스크립트
워드프레스 파일 상단에는 대개 이 줄이 있습니다.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
워드프레스를 거치지 않는 순수 PHP 스크립트에서 그런 파일을 require 하면, 이 줄이 그대로 실행되어 출력 0바이트 · 종료코드 0 으로 끝납니다. 에러도 경고도 없으므로 스크립트 로직을 먼저 의심하게 되고, 원인을 찾는 데 시간이 오래 걸립니다.
대처는 두 갈래입니다. 워드프레스가 필요하면 eval-file 로 돌리고, 필요 없으면 워드프레스 파일을 아예 include 하지 않는 자립형 스크립트로 만듭니다. 후자는 CI 에서 특히 유용한데, 데이터베이스도 워드프레스도 없이 몇 초 만에 끝나기 때문입니다 — 8회차에서 다시 다룹니다.
스크립트로 옮길 만한 작업이 무엇인지는 개발 워크플로우 아카이브에 사례가 있고, 우리가 같은 방식으로 만든 진단 도구들은 무료 도구에서 받을 수 있습니다.
다음 회차
스크립트를 쓰기 시작하면 곧 같은 스크립트를 두 번 돌리게 됩니다. 다음 회차는 멱등한 시드 — 두 번 돌려도 사본이 생기지 않게 만드는 방법이고, 여기에 조용한 함정이 여럿 있습니다.