目次
- 目次
- 環境
- 試行錯誤など
- 元記事のフォーマットを確認
- moment.jsの実力
- Cors
- Uncaught TypeError: Illegal invocation
- Base64エンコード
- ContentType
- どっこい本番環境では動かない
- 参考記事
友人が古いブログをWordPressに移行したいという。古いブログはMovableTypeなので、普通ならエクスポートインポートすればいいのだが、あまりに古いこともあり、もうMovableTypeの管理画面に入れないとのこと。画面から手作業でコピペをするのが辛いということだった。ふうむ。
環境
- MovableType
- WordPress 5.2
試行錯誤など
画面から取り出すということであれば、JavaScriptを使うのが良さそう。
ChromeのTampermonkeyであれば、JavaScriptをねじこんで実行させることができる。DOMごと引っこ抜くのはできそうだ。
データを抜いたら次はWordPressへの投稿だ。
最初は昔懐かしい「PressThis」ブックマークレットで突っ込めないかと思ったのだが、4.9で標準機能から外されてプラグインになっていたうえに、どうもHTMLを拾わず、プレーンテキストで読み込んでしまうみたい。これだとあまり旨味がない。
他にブックマークレットを探してもみたが、あまりこれ、というものがなかった。
Webであれこれ調べるうち、書き込むならREST APIを使えばいい、と思いついた。
最初はPHPを踏み台にするつもりだったが、JavaScriptからajaxで投げればなんとかなりそう。
つまずくポイント
Application Password」プラグインを導入
APIを使って投稿するためには、「Application Password」プラグインを導入し、ユーザーの設定画面で専用のパスワードを生成する必要がある。
Application Passwords – WordPress プラグイン | WordPress.org 日本語
APIに投げるパスワードにうっかりログインパスワードを使ってしまうと失敗する。WordPressのユーザー設定画面で、専用パスワードを発行してそれを使う。
パーマリンク設定を変更する
後述するが、パーマリンク設定がデフォルトの状態ではREST APIが無効化されているという不思議な仕様がある。まあ素人向けにはAPI開いておくの危険ということなのかもしれない。
WP REST APIで404が返ってくる。これはパーマリンク設定のせいだ! | PRESSMAN*Tech
元記事のフォーマットを確認
記事はh2が日付、h3がタイトル、本文はだいたいpタグだった。画像もpタグに囲まれている。
html4.1の時代なので、articleのように記事の明確な範囲を示すタグがないのは残念。幸い、記事のフッターのような感じでp.posted
があったので、これを目印に切り出すことにする。jQueryのnextUntil()
メソッドが使えそうだ。
記事の日付というか時刻表示もp.posted
からslice()
する方が早そう。
var date = $('p.posted')[0].innerHTML.slice(0,16);
moment.jsの実力
記事の日付にちょっと不整合があった。月は1桁か2桁なのだが、日付だけがなぜか半角スペースで桁揃えされている。
「2005年1月 9日」 「2005年10月10日」
これをJSで区別するのはめんどくさそうだなと思ったが、試しにMoment.jsを導入してみたら難なく差を吸収した。
var test = moment('2009年6月 2日 10:09','YYYY年M月D日 hh:mm');
これはありがたい。WordPressに出力する時は.format('YYYY-MM-DDThh:mm:00')
を使った。
Cors
Cross Origin Resource Sharing 。
テスト環境では別ドメインのサーバーに投げるので、functions.phpに記述する。
//Allow Cors for Tampermonkey function add_cors_http_header(){ header("Access-Control-Allow-Origin: http://www.original_blog_domain"); } add_action('init','add_cors_http_header');
本番は同じドメイン上にあるから大丈夫なはず、かな。
Uncaught TypeError: Illegal invocation
Base64エンコード
var url = blog_domain + '/wp-json/wp/v2/posts'; var Base64 = { encode: function(str) { return btoa(unescape(encodeURIComponent(str))); }, decode: function(str) { return decodeURIComponent(escape(atob(str))); } }; //passwordはApplication Passwordプラグインを導入してユーザー設定で取得 var authorizationToken = Base64.encode(username + ':' + password);
ContentType
contentType: 'application/json',
をajaxのパラメータに含める必要があった。これに気付かなかったばっかりに苦労した……。
$.ajax({ url : url, cache : false, type : 'POST', processData: false, beforeSend : function(request) { request.setRequestHeader("Authorization", 'Basic ' + }, contentType: 'application/json', dataType: "json", data:JSON.stringify({ title : "test", content : "<p>testtester</p>", status : "draft", date: '2019-11-12T23:23:00' }) }).done().fail().always();
とりあえずテスト投稿には成功。
どっこい本番環境では動かない
CORSのヘッダーが戻らずpreflight requestが拒否られる。
WP REST APIで404が返ってくる。これはパーマリンク設定のせいだ! | PRESSMAN*Tech
パーマリンク設定を変えたらたしかにCORSのヘッダーが表示されるようになった。
だが、Access-Control-Allow-Headersが戻ってないと言われる。ほかのヘッダーもどうも思った通りになっていない。
WordPressの方で出しているヘッダーがあって、置き換えられていないみたい。
未解決
一晩おいたらアクセス可能になった。なぜぇ?
何かのキャッシュの問題のようだけども。
参考記事
- 【WP REST API解説】投稿を作成する(/posts) | もじとばコム
- WordPressのREST APIを使ってみる | ITトラブル支援
- 文字列の一部分を切り出す(substr, substring, slice) – JavaScriptメモ
- A Pen by Captain Anonymous
- Moment.js | Docs
- CORS for the WordPress REST API · GitHub
- jquery - Enable CORS on JSON API Wordpress - Stack Overflow
- javascriptでBase64 - Qiita