WordPress:はてなブログからWordPressへワンクリックで移行

ある日突然、はてなブログから WordPress に移行しようと思い始めて準備中です。

はてなフォトライフからの一括画像移行とエクスポートデータの整形を一発でやってしまうツールをつくってみました。



過去の成果

WordPress に移行した場合、はてなブログのパーマリンクを維持できるかが一番の関心事だと思います。


「はてなブログ用リライトルールプラグイン」をつくりました。


www.imuza.com


はてなブログ to WordPress 移行ツール hatena2wp.php

今回の成果です。

はてなブログのエクスポートファイルからはてなフォトライフの URL を抜き出し、そのファイルを WordPress にコピーします。また、エクスポートファイルの整形、画像 URL の書き換え、見出しの書き換え、キーワードリンクを削除、Youtube 動画の https 化などを一括して行います。


ダウンロード

現在、Ver.2 になっています。やることは同じですが、画像の URL にドメイン名をつけるかどうかを選択できるようになっています。詳しくは次のリンク記事をご覧ください。


www.imuza.com


使い方

  • WordPress がインストールされたディレクトリに hatena2wp などのディレクトリをつくる
  • そのディレクトリに ftp で hatena2wp.php を入れる
  • WordPress の URL/hatena2wp/hatena2wp.php にアクセスする
  • はてなブログのエクスポートファイルを選択する
  • 終了を待つ
  • プラグイン「Movable Type・TypePad インポートツール」を使い、「mt-export.txt のインポート」をクリックする


次の画像のように進行します。

f:id:ausnichts:20210831134313j:plain


これで、はてなブログから WordPress への移行が完了します。はてなブログのパーマリンクを維持するには「はてなブログ用リライトルールプラグイン」を入れてください。


画像の移行の詳細

はてなブログのエクスポートファイルからはてなフォトライフの URL を抜き出し、その URL から WordPress の保存ディレクトリ wp-content/uploads/yyyy/mm を作成して保存しています。

もちろん、エクスポートファイルの URL もそのファイルを指し示すように書き換えています。


なお、移行したファイルは、そのままでは WordPress のメディアライブラリには表示されませんが表示には問題はありません。その画像を後に他の記事で使う予定がなければメディアライブラリに登録する必要はないと思います。


「Media from FTP」でメディアライブラリに一括登録する場合は、「日付」の選択や「 アップロードしたファイルを年月ベースのフォルダーに整理」のチェックを外さないとすべてのファイルが登録年月のフォルダに入ってしまい、画像が表示されなくなってしまいますので要注意です。


エクスポートファイルの整形の詳細

エスクポートファイルは次の整形をしています。


  • 画像の URL 変更、alt, title 属性削除
  • 不要なクラス削除
  • 見出しの変更 h3->h2, h4->h3, h5->h4
  • キーワードリンク削除
  • Youtube リンクを https に変更


整形後は、プラグイン「Movable Type・TypePad インポートツール」で即インポートできるように整形済みファイルを wp-content/mt-export.txt に保存しています。


終了後

作成した hatena2wp ディレクトリ、mt-export.txt を削除してください。


hatena2wp.php

やることは同じですが、Ver.2 が「WordPress:はてなブログからWordPressへの移行ツール Ver.2]」にあります。


(注)以下の「独自ドメイン」を WordPress を運用するご自身のドメインに変更してください(1ヶ所)


<?php
session_start();
$token = isset($_POST["token"]) ? $_POST["token"] : "";
$flg = false;
if ($token == ''){
    $token = uniqid('', true);
    $_SESSION['token'] = $token;
}else{
    $session_token = isset($_SESSION["token"]) ? $_SESSION["token"] : "";
    unset($_SESSION["token"]);
    if($token == $session_token) {
        $flg = true;
    }else{
        $token = uniqid('', true);
        $_SESSION['token'] = $token;
    }
}
?>

<!DOCTYPE html>
<html>
<head>
   <title>はてなブログからWordPressへ</title>
</head>
<body>
    <p>はてなブログから WordPress 移行のためのサポートツールです</p>
    <ul>
        <li>フォトライフ画像を wp-contents/uploads 以下の yyyy/mm ディレクトリにコピーします</li>
        <li>エクスポートファイルを WordPress 用に整形します
            <ul>
                <li>画像の URL 変更、alt, title 属性削除</li>
                <li>見出しの変更 h3->h2, h4->h3, h5->h4</li>
                <li>キーワードリンク削除</li>
                <li>Youtube リンクを https に変更</li>
            </ul>
        </li>
    </ul>
    <hr>
    <p>はてなブログのエクスポートファイルを指定してください</p>
    <p>画像ファイルのコピーは進行状態を 100ファイルずつ表示します<br>ただし、サーバーの設定によっては逐次表示されずに終了後一括表示される場合があります</p>
    <form enctype="multipart/form-data" action="hatena2wp.php" method="POST">
        <input type="hidden" name="token" value="<?php echo $token;?>">
        <input type="file" name="uploaded_file"></input><br>
        <input type="submit" value="Upload"></input>
    </form>

<?PHP
if($flg && !empty($_FILES['uploaded_file'])){
    $path = './';
    $path = $path . basename( $_FILES['uploaded_file']['name']);

    if(move_uploaded_file($_FILES['uploaded_file']['tmp_name'], $path)) {
        echo "ファイル " . basename( $_FILES['uploaded_file']['name']) . " がアップロードされました<br><br>";

        $pattern1 = '/(https?:\/\/cdn-ak\.f\.st-hatena.com\/images\/fotolife\/.+?(jpg|gif|png))/';
        $pattern2 = '/^https?:\/\/cdn-ak\.f\.st-hatena.com\/images\/fotolife\/.+?\/.+?\/(\d{4})(\d{2})\d{2}\/(.+)$/';
        $array = array();

        $hatena_text = file_get_contents($path);
        preg_match_all($pattern1, $hatena_text, $matches);
        $img_urls = array_unique($matches[1]);  
        $total = count($img_urls);
        $count = 0;

        echo "画像ファイルは " . $total . " ファイルあります<br>";
        echo "表示は 100ファイル移動ごとに更新します<br><br>";
        ob_flush();
        flush();
    
        foreach($img_urls as $url){
            if($img_data = @file_get_contents($url)){
                preg_match($pattern2, $url, $matches);
                $directory_name = '../wp-content/uploads/' . $matches[1] . '/' . $matches[2];
                $img_file_name = $directory_name . '/' . $matches[3];

                if(!is_dir($directory_name)){
                    mkdir($directory_name, 0705, true);
                }
                file_put_contents($img_file_name, $img_data);
                $array[] = $img_file_name;
                $count++;
                if($count % 100 == 0){
                    echo $count . " / " . $total . "<br>";
                    ob_flush();
                    flush();
                }
            }
        }
        echo $total . " / " . $total . "<br><br><hr>";

        $new_file = implode("\n", $array);
        $new_file_name = "images_list.txt";
        file_put_contents($new_file_name, $new_file);
        echo "アップロードしたファイル一覧を " . $new_file_name . " に保存しました<br><br><hr>";
      
        $patterns = array (
            '/https?:\/\/cdn-ak\.f\.st-hatena.com\/images\/fotolife\/.+?\/.+?\/(\d{4})(\d{2})\d{2}\/(.+\.(jpg|gif|png))/', 
            '/alt="f:id:.+?"/', 
            '/title="f:id:.+?"/', 
            '/ figure-image-fotolife mceNonEditable/', 
            '/ class="mceEditable"/', 
            '/<h3 /', 
            '/<\/h3>/', 
            '/<h4 /', 
            '/<\/h4>/', 
            '/<h5 /', 
            '/<\/h5>/', 
            '/<a .*href="http:\/\/d\.hatena\.ne\.jp\/keyword\/.+?".*?>(.+)?<\/a>/', 
            '/<iframe.+?youtube\.com\/embed\/(.+)?\?.+?<\/iframe>/'
            );
        $replace = array (
            'https://独自ドメイン/wp-content/uploads/$1/$2/$3', 
            'alt=""', 
            'title=""', 
            '', 
            '', 
            '<h2 ', 
            '</h2>', 
            '<h3 ', 
            '</h3>', 
            '<h4 ', 
            '</h4>', 
            '$1', 
            '<iframe src="https://www.youtube.com/embed/$1?enablejsapi=1" width="560" height="315" frameborder="0" allowfullscreen></iframe>'
            );

        $new_file = preg_replace($patterns, $replace, $hatena_text);

        $new_file_name = "../wp-content/mt-export.txt";
        file_put_contents($new_file_name, $new_file);
        echo "WordPress 用に整形したファイルを " . $new_file_name . " に保存しました<br>
          プラグイン「Movable Type・TypePad インポートツール」を使い、「mt-export.txt のインポート」をクリックしてください";

    } else{
        echo "ファイルをアップロードできませんでした";
    }
}
?>
</body>
</html>


ライセンス等

ご使用の場合は以下の注意事項をお守りください。

  • ライセンスは IMUZA.com にあります。
  • 紹介は歓迎ですが、バグ対応ができなくなりますので転載はしないでください。
  • 当記事の Javascript を使用してのはてなブログ用テーマの制作、公開は商用以外は自由です。ただし、記事内、あるいは紹介サイト内に IMUZA.com へのリンクを挿入してください。
  • 当記事の CSS への改変、公開は自由です。
  • 特別問題が発生することはありませんが自己責任でお使いください。
    問題が発生した場合は削除すればもとに戻ります。
  • お問い合わせ、バグの報告、仕様変更のご要望等は Contact Us までお願いします。