📑

WordPress でブログ移行してきた記事内の画像をうまくインポートする

2021/12/16に公開

標準のインポート/エクスポートが貧弱

WordPress には標準で記事、固定ページ等のインポート/エクスポート機能が存在していますが、XML 形式による出力のため、そのままでは上手く移行出来ない事が多いです。

具体的には、

  • アイキャッチが引き継がれない
  • メディア内の画像が引き継がれない
  • 記事内の画像が引き継がれない
  • パーマリンクを別で管理しているので、調整する必要がある

等、の問題が起こりやすいです。

賢明な方々であれば、All In One WP Migration の拡張を購入し、移行作業を行っていると思います。
ただ、事情により管理画面を渡してもらえない事も多いと思います。

記事内画像だけでもきちんと引き継ごう

アイキャッチについては、例えば記事内の最初の画像があれば、Auto Featured Image のようなプラグインを利用して再設定が可能です。
記事内画像は、元サイトと同一ドメインでの移行であっても、画像データの取得が必要です。

画像データの取得

影響が無いように、WordPress 設置フォルダ以下に、「_dev」フォルダのような名前で設置し、以下のようなスクリプトで動かします。

$wp_path = realpath("../");
require_once ($wp_path . '/wp-load.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 = $the_query->post->ID;

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

	$i = 0;
    foreach($matches[1] as $match_s){
        $ext_point = strrpos($match_s, ".");
        //gifは除外
        if($ext_point !== false){
            $str_point = $ext_point + 1;
            $ext_str     = substr($match_s, $str_point);
            if($ext_str === 'gif') continue;
        }
		$ext_str = parse_url($ext_str, PHP_URL_PATH);

        save_filesrc(regex_url($match_s), $post->ID.'-'.$i.'.'.$ext_str);
        ++$i;
    }
endwhile;
else:
endif;
wp_reset_postdata();

最初に WordPress 設置フォルダに対して wp-load.php をインクルードさせ、関数を使えるようにします。
通常投稿を全件取得して、記事内の「img src」を探して、URLを取得します。
Ameba とかからの移行だと、顔文字等が gif になっていたりして、要件的に削除する必要があったりするので、除外する場合を想定しています。

上記に使う独自関数は以下です。

/**
* ファイルを保存
*
*/
function save_filesrc(string $url, string $post_name) 
{
     $thumb_raw = curl_get_contents($url);
    $file_name_tmp = explode( '/', $url );
    $file_name_tmp = array_reverse( $file_name_tmp );
    $file_name = $file_name_tmp[0];
    $dir_list = scandir('./');
    if(!in_array('src',$dir_list,true)){
        mkdir('./src', 0705);
    }
    $save_dir_path = realpath('').'/src/';
    // // 画像保存
    if ( $thumb_raw )
    {
        $res = file_put_contents( $save_dir_path . $post_name, $thumb_raw );
    }
}

function curl_get_contents($url,$timeout = 60){
    $ch = curl_init();
    curl_setopt($ch,CURLOPT_URL,$url);
    curl_setopt($ch,CURLOPT_HEADER,false);
	curl_setopt($ch, CURLOPT_ENCODING, "");
    curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
    curl_setopt($ch,CURLOPT_TIMEOUT,$timeout);
    curl_setopt($ch,CURLOPT_FAILONERROR,true);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}

作業フォルダ内に「src」フォルダを作成し、そこに画像ファイルを吐き出します。
画像ファイルは日本語ファイルとかだと文字化けして面倒なので、記事ID-記事内順番.ext という名前付けをして、取得しています。
上記内容で一回実行して、きちんとsrcフォルダに取得出来たかを確認します。

本文内URLを書き換える

次に取得した画像URLに本文を書き換える必要があります。
先ほど画像ファイル名も変更したため、同名に書き換える必要があります。
また、作業フォルダとは別に wp-content/uploads/old_data/ 等の名前でフォルダを作成し、そこに設置する想定で変更します。

$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 = $the_query->post->ID;

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

	$i = 0;
    foreach($matches[1] as $match_s){
        $ext_point = strrpos($match_s, ".");
        //gifは除外
        if($ext_point !== false){
            $str_point = $ext_point + 1;
            $ext_str     = substr($match_s, $str_point);
            if($ext_str === 'gif') continue;
        }
		$ext_str = parse_url($ext_str, PHP_URL_PATH);

		$rp_title = home_url('/').'wp-content/uploads/old_data/'.$post->ID.'-'.$i.'.'.$ext_str;
		$post_content = str_replace($match_s, $rp_title, $post_content);
        ++$i;
    }

	global $wpdb;
	$result = $wpdb->update(
		$wpdb->posts,
		[
			'post_content' => $post_content,
		],
		[
			'ID' => $post_id,
		],
		['%s'],
		['%d']
	);



endwhile;
else:
endif;
wp_reset_postdata();

全件取得するループは同一ですが、$rp_title と、$post_content によって、本文内の画像URL書き換えを準備します。
次に wpdb Class を利用して本文を書き換えます。
書き換え後、srcフォルダ内の画像を wp-content/uploads/old_data/ に移動すれば完了です。
適時デバッグしながら進めると安全です。

Discussion