2026年6月26日

2026年6月26日

WordPressの添付ファイルエラーを解決する方法

はじめに

WordPressのメディアライブラリで画像をクリックすると「添付ファイルが見つかりません」と表示される・get_attached_file()が空を返してサムネイルが表示されない・投稿削除後もwp-content/uploads/に画像ファイルが残り続けてディスクを圧迫する・プログラムから添付ファイルを作成したのにメタデータが正しく生成されないといった問題は、WordPressの添付ファイル管理システムを理解することで解決できます。

症状・原因

  • 添付ファイルのメタデータ(_wp_attachment_metadata)が壊れているか存在しないため、画像情報を取得できない
  • ファイルを直接uploads/にコピーしたためWordPressのメディアライブラリに登録されていない
  • 投稿削除時にdelete_post()ではなくwp_delete_post()を使っていないため添付ファイルが残存する
  • _wp_attached_fileメタキーのパスが環境移行後に古い絶対パスのまま更新されていない

解決手順

ステップ1:添付ファイルの状態を診断する

# 添付ファイルのメタデータを確認
wp eval "
\$meta = wp_get_attachment_metadata(123);
print_r(\$meta);
"

# _wp_attached_file の値を確認(相対パス)
wp post meta get 123 _wp_attached_file

# 実際のファイルが存在するか確認
wp eval "
\$file = get_attached_file(123);
echo 'Path: ' . \$file . PHP_EOL;
echo 'Exists: ' . (file_exists(\$file) ? 'yes' : 'no') . PHP_EOL;
"

# 孤立した添付ファイルを特定(投稿が存在しない添付)
wp eval "
\$orphans = get_posts([
    'post_type'      => 'attachment',
    'post_parent'    => 0,
    'post_status'    => 'inherit',
    'posts_per_page' => 20,
    'fields'         => 'ids',
]);
echo 'Orphaned attachments: ' . implode(', ', \$orphans);
"

# メタデータがない添付ファイルを特定
wp post list --post_type=attachment --posts_per_page=50 --fields=ID,post_title

ステップ2:添付ファイルのメタデータを修復する

// ✅ 壊れたメタデータを再生成する
function my_repair_attachment_metadata(int $attachment_id): bool {
    require_once ABSPATH . 'wp-admin/includes/image.php';

    $file = get_attached_file($attachment_id);
    if (!$file || !file_exists($file)) {
        // _wp_attached_file が古いパスの場合は修正
        $uploads  = wp_upload_dir();
        $old_meta = get_post_meta($attachment_id, '_wp_attached_file', true);
        $new_path = $uploads['basedir'] . '/' . $old_meta;

        if (file_exists($new_path)) {
            update_post_meta($attachment_id, '_wp_attached_file', $old_meta);
            $file = $new_path;
        } else {
            return false;
        }
    }

    $metadata = wp_generate_attachment_metadata($attachment_id, $file);
    if (empty($metadata)) {
        return false;
    }

    return (bool) wp_update_attachment_metadata($attachment_id, $metadata);
}

// ✅ WP-CLI で全添付ファイルのメタデータを再生成
// wp media regenerate --yes
# メタデータを一括修復
wp eval "
\$ids = get_posts([
    'post_type'      => 'attachment',
    'post_mime_type' => 'image',
    'posts_per_page' => -1,
    'fields'         => 'ids',
]);
foreach (\$ids as \$id) {
    require_once ABSPATH . 'wp-admin/includes/image.php';
    \$file = get_attached_file(\$id);
    if (\$file && file_exists(\$file)) {
        \$meta = wp_generate_attachment_metadata(\$id, \$file);
        wp_update_attachment_metadata(\$id, \$meta);
        echo 'Fixed: ' . \$id . PHP_EOL;
    }
}
"

ステップ3:ファイルをメディアライブラリに正しく登録する

// ✅ 既存ファイルをメディアライブラリに登録する
function my_register_existing_file(string $file_path, int $parent_post_id = 0): int|WP_Error {
    require_once ABSPATH . 'wp-admin/includes/image.php';
    require_once ABSPATH . 'wp-admin/includes/file.php';

    if (!file_exists($file_path)) {
        return new WP_Error('file_not_found', 'ファイルが見つかりません: ' . $file_path);
    }

    $uploads  = wp_upload_dir();
    $filename = basename($file_path);
    $mime     = wp_check_filetype($filename)['type'] ?: 'application/octet-stream';

    // アップロードディレクトリ相対パスを計算
    $relative = str_replace($uploads['basedir'] . '/', '', $file_path);

    $attachment = [
        'post_mime_type' => $mime,
        'post_title'     => sanitize_file_name(pathinfo($filename, PATHINFO_FILENAME)),
        'post_content'   => '',
        'post_status'    => 'inherit',
        'post_parent'    => $parent_post_id,
    ];

    $attachment_id = wp_insert_attachment($attachment, $file_path, $parent_post_id);
    if (is_wp_error($attachment_id)) {
        return $attachment_id;
    }

    // _wp_attached_file を相対パスで登録
    update_post_meta($attachment_id, '_wp_attached_file', $relative);

    // メタデータを生成
    $metadata = wp_generate_attachment_metadata($attachment_id, $file_path);
    wp_update_attachment_metadata($attachment_id, $metadata);

    return $attachment_id;
}

ステップ4:孤立した添付ファイルを整理する

// ✅ 投稿が削除された添付ファイルを検出・削除
function my_cleanup_orphaned_attachments(bool $dry_run = true): array {
    $deleted = [];

    $attachments = get_posts([
        'post_type'      => 'attachment',
        'post_status'    => 'inherit',
        'post_parent'    => 0,
        'posts_per_page' => 100,
        'fields'         => 'ids',
    ]);

    foreach ($attachments as $id) {
        // この添付ファイルを参照している投稿があるか確認
        $used_in = get_post_meta($id, '_thumbnail_id', false);

        // メタデータ内で参照されているか確認(post_content内の画像など)
        global $wpdb;
        $referenced = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$wpdb->posts}
             WHERE post_content LIKE %s AND post_status = 'publish'",
            '%' . $wpdb->esc_like(wp_get_attachment_url($id)) . '%'
        ));

        if (empty($used_in) && !$referenced) {
            $deleted[] = $id;
            if (!$dry_run) {
                wp_delete_attachment($id, true); // true = ファイルも削除
            }
        }
    }

    return $deleted;
}

// ✅ 添付ファイルを投稿ごと削除(ファイルも削除)
function my_delete_attachment_with_file(int $attachment_id): bool {
    return (bool) wp_delete_attachment($attachment_id, true);
}

ステップ5:添付ファイルのURLとパスを正しく取得する

// ✅ 添付ファイルのURL・パスを取得する正しい方法
$attachment_id = 123;

// ファイルのURLを取得
$url = wp_get_attachment_url($attachment_id);

// 特定サイズのURLを取得
$thumb_url = wp_get_attachment_image_url($attachment_id, 'thumbnail');
$medium_url = wp_get_attachment_image_url($attachment_id, 'medium');

// img タグ全体を出力(srcset含む)
echo wp_get_attachment_image($attachment_id, 'large', false, [
    'class' => 'my-image',
    'alt'   => esc_attr(get_post_meta($attachment_id, '_wp_attachment_image_alt', true)),
]);

// ファイルの絶対パスを取得
$file_path = get_attached_file($attachment_id);

// MIME タイプを取得
$mime = get_post_mime_type($attachment_id);

// メタデータを取得(幅・高さ・サイズ一覧)
$meta = wp_get_attachment_metadata($attachment_id);
$width  = $meta['width']  ?? 0;
$height = $meta['height'] ?? 0;

// ✅ アイキャッチ画像として設定
set_post_thumbnail($post_id, $attachment_id);

// ✅ 特定投稿に紐付けた添付ファイル一覧を取得
$attached = get_posts([
    'post_type'   => 'attachment',
    'post_parent' => $post_id,
    'numberposts' => -1,
]);

注意事項

  • wp_delete_post()wp_delete_attachment()は異なります。添付ファイルを削除する場合は必ずwp_delete_attachment($id, true)を使用してください。第2引数trueを指定しないと投稿レコードは削除されますが実際のファイルはuploads/に残ります
  • 孤立した添付ファイルを大量に削除する場合は、必ずバックアップを取ってから$dry_run = falseに変更してください。wp_get_attachment_image_src()でショートコードやページビルダーから参照されているファイルは削除対象外にすること

まとめ

WordPressの添付ファイルエラーの解決は①wp_get_attachment_metadata()でメタ確認・get_attached_file()でパス存在確認・孤立添付をpost_parent:0で特定、②wp_generate_attachment_metadata()+wp_update_attachment_metadata()でメタ再生成・_wp_attached_fileの相対パスを修正、③wp_insert_attachment()+_wp_attached_file更新+wp_generate_attachment_metadata()で既存ファイルをライブラリ登録、④wp_delete_attachment($id, true)で添付ファイルとファイルを同時削除・post_content内での参照チェック後に孤立ファイルを整理、⑤wp_get_attachment_url()/wp_get_attachment_image_url()/get_attached_file()で正しくURL・パスを取得の手順で解決します。

お気軽にご相談ください

お見積りへ お問い合わせへ