こんにちは、アサヒリンクスです。この記事は、代表コバが現場で蓄積してきた知見をもとに、AIを活用して構成・執筆し、弊社にて最終チェックを行ったものです。
Claude Code を使って WordPress の投稿作業を自動化しているとき、「投稿直前に SEO チェックをし忘れた」「誤字があとから見つかった」「カテゴリの設定ミスで記事が正しく分類されなかった」という経験はないでしょうか。こうした投稿前チェックの抜け漏れは、手作業で確認する限りどうしても発生しやすくなります。
Claude Code には hooks という仕組みがあり、コマンド実行の前後に任意のスクリプトを差し込むことができます。この機能を使えば、WordPress への投稿前チェックを完全に自動化し、ヒューマンエラーを根本から排除することが可能です。本記事では、hooks の基本から実際の設定方法、SEO チェック・誤字検出・カテゴリ整合性確認の自動化まで、実装手順を順を追って解説します。
この記事でわかること
- Claude Code の hooks 機能の仕組みと種類
- settings.json での hooks 設定方法
- 投稿前 SEO チェックを自動化する bash スクリプトの書き方
- 誤字・表記ゆれ検出の自動化手順
- カテゴリ・タクソノミー整合性の自動検証
- 複数チェックをまとめてパイプライン化する方法
- 実運用でのトラブルシューティングとベストプラクティス
目次
- Claude Code の hooks とは何か
- hooks の設定ファイルと基本構文
- 投稿前 SEO チェックを hooks で自動化する
- 誤字・表記ゆれ検出を自動化する
- カテゴリ・タクソノミー整合性の自動検証
- 複数チェックをパイプライン化する
- 実運用での注意点とトラブルシューティング
- まとめ
Claude Code の hooks とは何か
Claude Code の hooks は、Claude がツール呼び出しを行う前後に、任意のシェルスクリプトやコマンドを自動実行できる仕組みです。WordPress の投稿処理を例に取ると、「WP-CLI の post create コマンドが実行される直前に HTML ファイルを検査する」「投稿完了後にサイトマップを更新する」といった処理を、人手を介さず自動的に差し込めます。
hooks が特に強力なのは、チェックをパスしなければ元のコマンドをブロックできる点です。SEO スコアが基準を下回る記事や、誤字が残っている HTML ファイルが検出された場合に、投稿処理そのものを止めることができます。これにより「チェックリストを見落とした」「急いでいたので確認を省いた」といった運用上の抜け漏れがなくなります。
hooks の種類:PreToolUse と PostToolUse
現時点で利用できる主要な hooks イベントは次の 2 種類です。
- PreToolUse:Claude がツール(Bash、Write、Edit など)を呼び出す直前に実行される。ここで exit code が 0 以外を返すと、元のツール呼び出しはキャンセルされる
- PostToolUse:ツール実行が完了した直後に実行される。後処理・通知・ログ記録などに使う
WordPress 投稿前チェックの自動化は、主に PreToolUse を使います。「WP-CLI が呼ばれる直前に HTML ファイルを検査し、問題があれば投稿をキャンセルする」という流れです。
hooks が解決する現場の課題
代表コバが対応してきた案件では、自動投稿パイプラインを導入した後も「公開済み記事に誤字が残っていた」「meta description が空のまま投稿された」という問題が一定頻度で発生していました。原因を追うと、生成 AI が出力した HTML を人が目視確認せずそのまま WP-CLI に渡していたケースがほとんどでした。hooks によるゲートを設けることで、こうした問題を投稿前の段階で確実に検知できるようになります。
hooks の設定ファイルと基本構文
Claude Code の hooks は .claude/settings.json(プロジェクトローカル)または ~/.claude/settings.json(グローバル)に記述します。プロジェクト固有のチェックロジックはプロジェクトローカルに、すべての Claude Code 作業で共通して使いたいものはグローバルに置くのが基本方針です。
settings.json の基本構文
hooks の設定は hooks キーの下に、イベント種別をキーとして配列で記述します。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/path/to/pre_check.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/path/to/post_notify.sh"
}
]
}
]
}
}
matcher にはツール名(Bash、Write、Edit、Read など)を指定します。"*" と指定するとすべてのツール呼び出しに対して hooks が発火します。
hooks スクリプトへの入力と出力
hooks スクリプトは 標準入力(stdin)から JSON 形式でコンテキスト情報を受け取ります。Bash ツールの PreToolUse であれば、実行されようとしているコマンド文字列が含まれます。
# hooks スクリプトが受け取る stdin の例(Bash ツールの場合)
{
"tool_name": "Bash",
"tool_input": {
"command": "/usr/local/bin/wp post create /tmp/article_14.html --post_type=tips ..."
}
}
スクリプトの終了コードによって Claude Code の挙動が変わります。
exit 0:問題なし。元のツール呼び出しを続行するexit 2:ブロック。元のツール呼び出しをキャンセルし、スクリプトの stdout を Claude へのフィードバックとして渡すexit 1(その他の非ゼロ):hooks 自体のエラーとして扱われ、ツール呼び出しは続行される(設定次第で挙動が変わるため、明示的に exit 2 を使うのが推奨)
Tips:フィードバック文字列を stdout に出力しておくと、Claude がその内容を読んで「何が問題だったか」を把握し、修正案を提案してくれます。チェックの理由を日本語で書いておくと、そのまま Claude への指示として機能します。
投稿前 SEO チェックを hooks で自動化する
WordPress 記事の SEO 品質を自動検査する hooks スクリプトを作成します。ここでは HTML ファイルに対して、meta description の有無・文字数・H2 タグ数・本文文字数の 4 項目をチェックします。
SEO チェックスクリプトの実装
以下のスクリプトを /var/www/html/seo-auto/hooks/pre_seo_check.sh に配置します。
#!/bin/bash
# pre_seo_check.sh — WordPress 投稿前 SEO チェック hooks
# 使用方法:stdin から Claude Code の tool_input JSON を受け取る
set -euo pipefail
# stdin から JSON を読み込む
INPUT=$(cat)
# Bash ツールのコマンド文字列を取得
COMMAND=$(echo "$INPUT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('tool_input',{}).get('command',''))")
# wp post create を含むコマンドのみ対象にする
if ! echo "$COMMAND" | grep -q "wp post create"; then
exit 0
fi
# HTML ファイルパスを抽出(/tmp/article_*.html 形式を想定)
HTML_FILE=$(echo "$COMMAND" | grep -oP '/tmp/article_\d+\.html' | head -1)
if [ -z "$HTML_FILE" ] || [ ! -f "$HTML_FILE" ]; then
echo "【SEO チェック】HTML ファイルが見つかりません: $HTML_FILE"
exit 2
fi
ERRORS=()
# 1. META_DESC コメント行の有無を確認
META_DESC=$(grep -oP '(?<=)' "$HTML_FILE" | head -1)
if [ -z "$META_DESC" ]; then
ERRORS+=("META_DESC コメントが設定されていません。 を冒頭に追加してください。")
else
META_LEN=${#META_DESC}
if [ "$META_LEN" -lt 70 ]; then
ERRORS+=("META_DESC が短すぎます(現在 ${META_LEN} 字)。70 字以上を推奨します。")
fi
if [ "$META_LEN" -gt 160 ]; then
ERRORS+=("META_DESC が長すぎます(現在 ${META_LEN} 字)。160 字以内に収めてください。")
fi
fi
# 2. H2 タグ数を確認
H2_COUNT=$(grep -c ']*>//g' "$HTML_FILE" | tr -d '[:space:]' | wc -c)
if [ "$CHAR_COUNT" -lt 4000 ]; then
ERRORS+=("本文文字数が不足しています(現在 約 ${CHAR_COUNT} 字)。5000 字以上を目標にしてください。")
fi
# 4. TITLE コメント行の有無を確認
TITLE=$(grep -oP '(?<=)' "$HTML_FILE" | head -1)
if [ -z "$TITLE" ]; then
ERRORS+=("TITLE コメントが設定されていません。 を冒頭に追加してください。")
fi
# エラーがある場合はブロック
if [ ${#ERRORS[@]} -gt 0 ]; then
echo "【SEO チェック失敗】以下の問題を修正してから再投稿してください:"
for ERR in "${ERRORS[@]}"; do
echo " - $ERR"
done
exit 2
fi
echo "【SEO チェック OK】meta_desc=${META_LEN}字 / H2=${H2_COUNT}個 / 本文≈${CHAR_COUNT}字"
exit 0
settings.json への登録
作成したスクリプトに実行権限を付与し、.claude/settings.json に登録します。
chmod +x /var/www/html/seo-auto/hooks/pre_seo_check.sh
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/var/www/html/seo-auto/hooks/pre_seo_check.sh"
}
]
}
]
}
}
Tips:スクリプトのデバッグ中は exit 2 の代わりに exit 0 でいったん通過させながら、stdout のログを確認すると効率的です。本番移行前に exit 2 に切り替えてゲート機能を有効にしてください。
誤字・表記ゆれ検出を自動化する
AI が生成した記事であっても、学習データ由来の表記ゆれや固有名詞のミスが混入することがあります。特に「Anthropic」「Claude」「WordPress」などのブランド名の誤記、カタカナ表記の揺れ(「システム」vs「システム」などの全角半角混在)は自動検出が有効です。
表記ゆれ辞書と検出スクリプトの実装
検出パターンを JSON で管理し、bash スクリプトから参照する構成にします。辞書ファイルを /var/www/html/seo-auto/data/typo_rules.json に作成します。
{
"rules": [
{
"pattern": "アンソロピック",
"correct": "Anthropic",
"description": "社名の誤記"
},
{
"pattern": "クロード",
"correct": "Claude",
"description": "製品名の誤記(カタカナ化)"
},
{
"pattern": "ワードプレス",
"correct": "WordPress",
"description": "製品名の誤記"
},
{
"pattern": "WP CLI",
"correct": "WP-CLI",
"description": "ツール名の表記ゆれ(ハイフン抜け)"
},
{
"pattern": "Github",
"correct": "GitHub",
"description": "大文字小文字の誤り"
},
{
"pattern": "javascript",
"correct": "JavaScript",
"description": "大文字小文字の誤り"
},
{
"pattern": "API Key",
"correct": "API キー",
"description": "表記ゆれ(日本語文中では統一)"
}
]
}
次に検出スクリプト /var/www/html/seo-auto/hooks/pre_typo_check.sh を作成します。
#!/bin/bash
# pre_typo_check.sh — 誤字・表記ゆれ検出 hooks
set -euo pipefail
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('tool_input',{}).get('command',''))")
if ! echo "$COMMAND" | grep -q "wp post create"; then
exit 0
fi
HTML_FILE=$(echo "$COMMAND" | grep -oP '/tmp/article_\d+\.html' | head -1)
if [ -z "$HTML_FILE" ] || [ ! -f "$HTML_FILE" ]; then
exit 0
fi
RULES_FILE="/var/www/html/seo-auto/data/typo_rules.json"
ERRORS=()
# JSON から各ルールを読み込んで検査
while IFS= read -r PATTERN; do
CORRECT=$(python3 -c "
import json, sys
rules = json.load(open('$RULES_FILE'))['rules']
p = '''$PATTERN'''
for r in rules:
if r['pattern'] == p:
print(r['correct'])
break
")
DESC=$(python3 -c "
import json, sys
rules = json.load(open('$RULES_FILE'))['rules']
p = '''$PATTERN'''
for r in rules:
if r['pattern'] == p:
print(r['description'])
break
")
if grep -q "$PATTERN" "$HTML_FILE" 2>/dev/null; then
# コードブロック内の出現は除外(false positive を減らす)
MATCH_OUTSIDE_CODE=$(sed 's/]*>.*<\/pre>//g' "$HTML_FILE" | grep -c "$PATTERN" || true)
if [ "$MATCH_OUTSIDE_CODE" -gt 0 ]; then
ERRORS+=("「${PATTERN}」→「${CORRECT}」に修正してください(${DESC})")
fi
fi
done < <(python3 -c "import json; [print(r['pattern']) for r in json.load(open('$RULES_FILE'))['rules']]")
if [ ${#ERRORS[@]} -gt 0 ]; then
echo "【表記チェック失敗】以下の表記ゆれを修正してください:"
for ERR in "${ERRORS[@]}"; do
echo " - $ERR"
done
exit 2
fi
echo "【表記チェック OK】誤字・表記ゆれは検出されませんでした"
exit 0
Tips:辞書ファイル(typo_rules.json)はプロジェクトごとに育てていくのが効果的です。新しい表記ゆれが見つかったら追加し、チームで共有できる「表記ガイドライン」として機能させると、長期的な品質維持につながります。
カテゴリ・タクソノミー整合性の自動検証
WordPress でカスタム投稿タイプを運用している場合、投稿時に誤ったカテゴリスラッグを指定してしまうミスが発生しやすくなります。WP-CLI のコマンド引数に存在しないスラッグを渡してもエラーにならず、単に未分類のまま投稿されてしまうことがあるため、hooks でのゲートが有効です。
カテゴリ整合性チェックスクリプトの実装
有効なカテゴリスラッグのリストを JSON で管理し、投稿コマンド中のスラッグと照合します。
#!/bin/bash
# pre_category_check.sh — タクソノミー整合性チェック hooks
set -euo pipefail
VALID_CATS_JSON='/var/www/html/seo-auto/data/valid_categories.json'
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('tool_input',{}).get('command',''))")
# wp post term add を含むコマンドのみ対象
if ! echo "$COMMAND" | grep -q "wp post term add"; then
exit 0
fi
# コマンドからスラッグを抽出
# 例: wp post term add 123 tips_cat claude-code --by=slug
SLUG=$(echo "$COMMAND" | grep -oP 'wp post term add \d+ \S+ \K\S+')
if [ -z "$SLUG" ]; then
exit 0
fi
# 有効スラッグリストと照合
IS_VALID=$(python3 -c "
import json
cats = json.load(open('$VALID_CATS_JSON'))
slug = '$SLUG'
print('yes' if slug in cats['tips_cat'] else 'no')
")
if [ "$IS_VALID" = "no" ]; then
VALID_LIST=$(python3 -c "import json; print(', '.join(json.load(open('$VALID_CATS_JSON'))['tips_cat']))")
echo "【カテゴリチェック失敗】スラッグ「${SLUG}」は tips_cat に存在しません。"
echo "有効なスラッグ: ${VALID_LIST}"
exit 2
fi
echo "【カテゴリチェック OK】スラッグ「${SLUG}」は有効です"
exit 0
有効カテゴリの定義ファイル /var/www/html/seo-auto/data/valid_categories.json は次のように管理します。
{
"tips_cat": [
"claude-use",
"industry-cases",
"ai-tools",
"ai-basics",
"ai-vendor",
"claude-code"
]
}
WP-CLI と連携してリアルタイムにカテゴリを取得する方法
静的な JSON 管理ではなく、WP-CLI を呼び出してサイトの実際のタクソノミーを動的に取得する方法もあります。本番環境のカテゴリ構成が変わるたびに JSON を手動更新する手間が省けます。
# 動的取得版(WP-CLI を使用)
VALID_SLUGS=$(/usr/local/bin/wp term list tips_cat \
--path=/var/www/html/asahilinks \
--field=slug \
--allow-root 2>/dev/null | tr '\n' ',')
if ! echo ",$VALID_SLUGS," | grep -q ",${SLUG},"; then
echo "【カテゴリチェック失敗】スラッグ「${SLUG}」は登録されていません。"
echo "現在の有効スラッグ: ${VALID_SLUGS%,}"
exit 2
fi
Tips:WP-CLI の動的取得はサイトへのアクセスが発生するため、処理時間が数秒かかることがあります。高頻度に投稿するパイプラインでは、静的 JSON との組み合わせ(起動時に JSON を生成・キャッシュ)がバランスが取れた選択肢です。
複数チェックをパイプライン化する
SEO チェック・誤字検出・カテゴリ整合性の 3 つをそれぞれ独立したスクリプトで作成した場合、settings.json では複数の hooks を配列で並べることで、順番に実行させることができます。
settings.json で複数 hooks を直列実行する
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/var/www/html/seo-auto/hooks/pre_seo_check.sh"
},
{
"type": "command",
"command": "/var/www/html/seo-auto/hooks/pre_typo_check.sh"
},
{
"type": "command",
"command": "/var/www/html/seo-auto/hooks/pre_category_check.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/var/www/html/seo-auto/hooks/post_publish_notify.sh"
}
]
}
]
}
}
配列に並べた hooks は上から順に実行され、いずれかが exit 2 を返した時点でそれ以降の hooks と元のツール呼び出しがキャンセルされます。
投稿完了後の通知スクリプト(PostToolUse)
PostToolUse 側では、投稿完了の通知ログを残すスクリプトを配置します。
#!/bin/bash
# post_publish_notify.sh — 投稿完了後の通知ログ
set -euo pipefail
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('tool_input',{}).get('command',''))")
if ! echo "$COMMAND" | grep -q "wp post create"; then
exit 0
fi
# 投稿ログに記録
LOG_FILE="/var/log/wp-auto-post/post_log.txt"
mkdir -p "$(dirname "$LOG_FILE")"
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$TIMESTAMP] 投稿コマンド実行: $COMMAND" >> "$LOG_FILE"
exit 0
全チェックをひとつのラッパースクリプトにまとめる方法
チェック数が増えてきた場合、個別スクリプトを呼び出すラッパーを 1 本作成し、settings.json のエントリを 1 つに絞る方法もあります。
#!/bin/bash
# pre_all_checks.sh — 全 pre チェックのラッパー
INPUT=$(cat)
run_check() {
local SCRIPT="$1"
local RESULT
RESULT=$(echo "$INPUT" | bash "$SCRIPT" 2>&1)
local EXIT_CODE=$?
if [ $EXIT_CODE -ne 0 ]; then
echo "$RESULT"
exit $EXIT_CODE
fi
echo "$RESULT"
}
run_check "/var/www/html/seo-auto/hooks/pre_seo_check.sh"
run_check "/var/www/html/seo-auto/hooks/pre_typo_check.sh"
run_check "/var/www/html/seo-auto/hooks/pre_category_check.sh"
exit 0
Tips:ラッパー方式にすると、settings.json を変更せずにチェックロジックを追加・削除できます。チェック内容が今後増える見込みがあるプロジェクトでは、最初からラッパー方式を採用しておく方が保守しやすくなります。
実運用での注意点とトラブルシューティング
hooks を本番の自動投稿パイプラインに組み込む際、いくつかの点に注意が必要です。実際に運用してみて気づいた落とし穴とその対処方法をまとめます。
よくある問題と対処方法
① stdin が空になる問題
hooks スクリプトは stdin から JSON を受け取りますが、Claude Code のバージョンや設定によっては stdin が空で渡されるケースがあります。スクリプトの冒頭で INPUT が空かどうかを確認し、空の場合は exit 0 で素通りさせる防御コードを入れておきましょう。
INPUT=$(cat)
if [ -z "$INPUT" ]; then
exit 0
fi
② スクリプトのパーミッションエラー
Claude Code が hooks を実行するユーザーと、スクリプトのオーナーが異なると Permission denied エラーになります。スクリプトに実行権限を付与し、必要に応じて所有者を合わせてください。
chmod +x /var/www/html/seo-auto/hooks/*.sh
chown root:root /var/www/html/seo-auto/hooks/*.sh
③ 文字数カウントがずれる問題
wc -c はバイト数を返すため、日本語(UTF-8、3バイト/文字)を含む本文では文字数より大きい数値になります。日本語文字数を正確に計測するには python3 を使います。
CHAR_COUNT=$(sed 's/<[^>]*>//g' "$HTML_FILE" | python3 -c "
import sys
text = sys.stdin.read()
print(len(text.replace(' ','').replace('\n','').replace('\t','')))
")
hooks のデバッグ方法
hooks が期待通りに動作しないときは、スクリプトを直接 bash で実行して入力 JSON を確認します。テスト用の入力 JSON を用意してパイプで渡すと素早くデバッグできます。
# デバッグ用テスト実行
echo '{
"tool_name": "Bash",
"tool_input": {
"command": "/usr/local/bin/wp post create /tmp/article_14.html --path=/var/www/html/asahilinks --post_type=tips"
}
}' | bash /var/www/html/seo-auto/hooks/pre_seo_check.sh
echo "Exit code: $?"
Tips:本番運用に移行する前に、正常系・異常系の両方でテストを行ってください。特に「チェックが誤って通過する(false negative)」ケースより「正常な投稿がブロックされる(false positive)」の方が運用上の影響が大きいため、チェックの閾値は少し緩めに設定し、運用しながら締めていくアプローチが安全です。
まとめ
Claude Code の hooks を活用することで、WordPress への投稿前チェックを完全に自動化し、ヒューマンエラーを防ぐ仕組みを構築できます。本記事で紹介した実装をまとめると次のようになります。
- PreToolUse hooks:Bash ツールが実行される直前に SEO チェック・表記ゆれ検出・カテゴリ整合性確認を自動実行し、問題があれば投稿をブロック
- settings.json:プロジェクトローカルの
.claude/settings.jsonに複数の hooks スクリプトを配列で登録し、順番に実行 - 辞書ファイルの活用:チェックルールを JSON で外部管理することで、スクリプトを変更せずにルールを追加・修正できる
- ラッパースクリプト:チェック数が増えた場合はラッパーにまとめて settings.json をシンプルに保つ
自動化された投稿パイプラインは、記事数が増えるほど手作業チェックのコストが高くなる問題を解決します。今回紹介した hooks ベースのゲートを導入することで、「公開後に問題を発見して修正する」コストを大幅に削減できます。
本記事は代表コバの現場知見をもとに AI で構成し、弊社にて最終確認を行っています。
Claude Code を活用した自動化の仕組みの構築や、WordPress 運用の効率化についてご興味がある方は、お気軽にご相談ください。費用感だけ知りたい方のご相談も歓迎しています。
→ お問い合わせはこちら