😽

WordPress で他サイトからのブログ記事インポートで、画像をメディアに追加する

2024/06/11に公開

Tl,DR

  • プラグインなどを使わず標準機能で記事移設したい
  • しかし画像はそのまま移設されない事が多い
  • 記事移設後にダウンロードして、出来ればメディアに追加したい

以下のコードを貼り付けて実行

どのファイルでも構わないですが、アクセスして実行したいので、一旦page.phpに貼り付けて、固定ページアクセスで実行されるようにしてみます。

page.php
$args = [
	'posts_per_page' => -1,
];
$the_query = new WP_Query($args);

if ($the_query->have_posts()) :
	while ($the_query->have_posts()) :
		$the_query->the_post();

		$post_id = get_the_ID();
		$post_content = get_post_field('post_content', $post_id);
		$matches = [];
		$output = preg_match_all('/<img.*?src\s*=\s*[\"|\'](.*?)[\"|\'].*?>/i', $post_content, $matches);
		$first_img_set = false;

		if (!empty($matches[1])) {
			// 画像URLを新しいURLに置き換える処理
			$updated_post_content = replace_post_image_urls($post_id, $post_content, $matches);
		}

	endwhile;
endif;
wp_reset_postdata();

// 投稿内容中の画像URLを新しいURLに置き換える部分の更新
function replace_post_image_urls($post_id, $post_content, $matches)
{
    foreach ($matches[1] as $index => $image_url) {
        $original_url = get_original_image_url($image_url);
        $attach_id = import_image_to_media_library($original_url, $post_id);
        if (!is_wp_error($attach_id)) {
            // インポートした画像のURLを取得
            $new_image_url = wp_get_attachment_url($attach_id);

            // srcsetの生成
            $image_meta = wp_get_attachment_metadata($attach_id);
            $srcset = wp_get_attachment_image_srcset($attach_id, 'full', $image_meta);

            // 投稿内容中の画像タグを新しいタグに置き換える
            $new_img_tag = sprintf('<img src="%s" srcset="%s">', $new_image_url, $srcset);
            $post_content = str_replace($matches[0][$index], $new_img_tag, $post_content);
        }
    }

    // 投稿内容を更新
    wp_update_post([
        'ID' => $post_id,
        'post_content' => $post_content,
    ]);

    return $post_content; // 更新された投稿内容を返す
}


/**
 * 画像URLから元の画像のURLを生成します。
 *
 * @param string $url 画像のURL
 * @return string 元の画像のURL
 */
function get_original_image_url(string $url): string
{
    // URLからファイル名を抽出
    $path = parse_url($url, PHP_URL_PATH);
    $filename = basename($path);

    // サイズ指定があるファイル名から元のファイル名を導出
    $original_filename = preg_replace('/-\d+x\d+(\.\w+)$/', '$1', $filename);

    // 元のファイル名をパスに再組み込む
    $original_url = str_replace($filename, $original_filename, $url);

    return $original_url;
}

function import_image_to_media_library($image_url, $post_id)
{
    require_once(ABSPATH . 'wp-admin/includes/image.php');
    require_once(ABSPATH . 'wp-admin/includes/file.php');
    require_once(ABSPATH . 'wp-admin/includes/media.php');

    // 画像ファイルをサーバーにダウンロード
    $tmp = download_url($image_url);

    // ダウンロードエラーをチェック
    if (is_wp_error($tmp)) {
        // エラーがあればそのまま返す
        return $tmp;
    }

    $file_array = array(
        'name' => basename($image_url), // 画像ファイル名
        'tmp_name' => $tmp, // ダウンロードした一時ファイルのパス
    );

    // メディアライブラリにファイルを登録
    $id = media_handle_sideload($file_array, $post_id);

    // ファイル操作後のエラーチェック
    if (is_wp_error($id)) {
        // エラーがあれば一時ファイルを削除し、エラーを返す
        if (file_exists($tmp)) {
            unlink($tmp);
        }
        return $id;
    }

    // 成功した場合、一時ファイルがまだ存在するなら削除
    if (file_exists($tmp)) {
        unlink($tmp);
    }

    return $id; // メディアライブラリに登録した画像のIDを返す
}

tmp = download_url(image_url);
ここでファイルをダウンロード出来ればそのまま進みますが、ダウンロード出来ない場合は失敗します。
遭遇したケースだと、何故か src="/wp-content" となっていたので、

function regexImgURL(string $url)
{
	$url = 'https://www.example.com/' . $url;
	if (file_get_contents($url, false, null, 0, 1)) {
		return esc_url($url);
	}
}

のように元URLに正規化する関数で、ダウンロード出来るようにすれば、うまく動くと思います

All in One WP Migration などのプラグインが普及して通常そちらを使った方がスムーズで楽だと思います。しかし、一部投稿タイプの記事だけ移設したい、などの要求があるときに、標準機能でエクスポート/インポートして、画像だけ処理するという方法は必要で便利だと思います

Discussion