修正したWordPress Postの最新版は下記になります。
ここ3回(その1・その2・その2)では、WordPressの記事をVS Codeで作成できる拡張機能であるWordPress Post拡張機能を修正したことを紹介しました。
これでひとまず私の不満は解消したのですが、実際にWordPress Post拡張機能を利用してWordPressの記事を作成しているともう一つ不満が出てきました。今回はこれに対処したいと思います。
新たな不満点
私がWordPressで利用しているテーマであるCocoonでは「アイコンボックス」「案内ボックス」というスタイルが用意されています。
例えばHTMLで
<div class="information-box">補足情報</div>
と記載すると、
と表示されます。
私はこの「アイコンボック」や「案内ボックス」をブログで多用していますが、Markdownでは入力できないのが難点です。
結局、Markdownで記述した記事をWordPressにポストしてから、HTMLのコードを挿入して「アイコンボックス」「案内ボックス」を実現していました。
しかし、できればVS Code上での作業で完結させたいところです。
アイコンボックス・案内ボックスのサポート
アイコンボックス・案内ボックスをサポートするためには、Markdownの特定の領域を指定し、その領域をHTMLタグではさむ必要があります。
ここでは「ブロックレベルのHTMLタグではさむ」ことをカスタムコンテナと呼ぶことにします。
調べてみるとmarkdon-it(この拡張機能でMarkdownをHTMLに変換するために利用しているパッケージ)のプラグインとしてmarkdown-it-containerというのがあることがわかりました。
このプラグインを使うとMarkdownで
::: warning
here be dragons
:::
と記述すると
<div class="warning">
here be dragons
</div>
というようなカスタムコンテナを作成することができます。
ここではHTMLタグとして「<div class=”warning”>」と「</div>」が利用されていますが、これはカスタマイズ可能です。
このプラグインを使えば、やりたいことは実現できそうです。
修正の方針
今回は次のような方針で修正を行うことにしました。
- カスタムコンテナを利用するかどうかを設定で選べるようにする(デフォルトは「オフ」)。
- カスタムコンテナの設定(名前・開始タグ・終了タグ)は複数できるようにする
- カスタムコンテナの設定に従い、markdown-it-containerを使って「:::」で指定された領域を「開始タグ」「終了タグ」で挟んだHTMLとして出力する。
- カスタムコンテナの設定で「開始タグ」と「終了タグ」を省略したときは、開始タグとして「<div class=”名前”>」を、終了タグとして「</div>」を使う。
とりあえず設定できるカスタムコンテナの数は5個とすることにしました。
なお、新設する設定項目でデフォルト値を選択すると、オリジナルのWordPress Post拡張機能と同じ動作となるようにします。
ソースコードの修正
この修正を行ったブランチは下記になります。
package.json
package.jsonでは、拡張機能の設定項目の追加と、動作に必要なパッケージ(ライブラリ)の追加のために変更します。
設定項目の追加
設定項目の追加はpackage.jsonを変更することで行います。
今回は「contributes」→「configuration」→「properties」に下記の項目を追加しました。
"wordpress-post.customContainer.no1": {
"type": "object",
"description": "Create block-level custom containers #1.\nIf name is blank, this custom container is disabled.\nIf both openingTag and closingTag are blank, default container (<div class=\"name\"> and </div>) is used.",
"properties": {
"name": {
"type": "string",
"description": "Name of custom container #1. If blank, this container is disabled."
},
"openingTag": {
"type": "string",
"description": "Opening HTML code of custom container #1."
},
"closingTag": {
"type": "string",
"description": "Closing HTML code of custom container #1."
}
},
"additionalProperties": false,
"default" : {
"name" : "",
"openingTag" : "",
"closingTag" : ""
}
},
"wordpress-post.customContainer.no2": {
// 省略
},
"wordpress-post.customContainer.no3": {
// 省略
},
"wordpress-post.customContainer.no4": {
// 省略
},
"wordpress-post.customContainer.no5": {
// 省略
},
「wordpress-post.customContainer.no1」は1つ目のカスタムコンテナの設定です。この設定は「name」「openingTag」「closingTag」の三つから構成されています。
「name」はこのカスタムコンテナの名前で、「:::」の後に「name」で指定された文字列を発見するとカスタムコンテナとして認識されます。「name」が未指定(空欄)の場合はこのカスタムコンテナは無効化されます。
「openingTag」と「closingTag」はカスタムコンテナの開始タグと終了タグで、「:::」で囲まれた範囲のMarkdownはここで指定されたHTMLタグに挟まれてHTML化されます。
openingTagとclosingTagに指定されたタグはHTMLにそのまま出力されます。
openingTagとclosingTagの内容の正当性はチェックしていないので、不正なタグ・壊れたタグを指定された場合は、この拡張機能で出力されたHTML自体がおかしくなります。
なお、「openingTag」と「closingTag」が省略された場合は、「name」を利用して「<div class=”nameで指定した名前”>」と「</div>」が利用されます。
「wordpress-post.customContainer.no2」~「wordpress-post.customContainer.no5」の内容は「wordpress-post.customContainer.no1」と基本的に同じになるので、説明を省略します。
パッケージの追加
今回はカスタムコンテナを実現するために「markdown-it-container」というパッケージを利用しました。
利用するパッケージの情報はpackage.jsonの「dependencies」に次のように追加します。
"markdown-it-container": "^3.0.0"
なお、package.jsonの「dependencies」を変更した場合には、「npm install」を実行する必要があるようです。
「npm install」を実行すると、package-lock.jsonが更新されるので、このファイルもコミットしておきます。
context.ts
この拡張機能では設定項目関係の情報を取得する関数がcontext.tsに記述されています。
今回はこのファイルにpackage.jsonで追加した設定項目を取得するための関数を追加しました。
getCustomContainer(no : number) : [string, string, string] {
const key : string = "customContainer.no" + no.toString();
const conf = vscode.workspace.getConfiguration(this.prefixOfSettings);
const name : string = conf.get<string>(key + ".name", "");
const openingTag : string = conf.get<string>(key + ".openingTag", "");
const closingTag : string = conf.get<string>(key + ".closingTag", "");
return [name, openingTag, closingTag];
}
この関数では引数に取得したいカスタムコンテナの番号を指定すると、戻り値として「name」「openingTag」「closingTag」の設定値を返すというものです。
post.ts
post.tsはこの拡張機能のメイン動作を記述しているファイルです。
元々のコードではMarkdownをHTMLに変換する処理は
postData["content"] = MarkdownIt().render(markdown.content);
となっていました。
この部分を次のように変更しました。
const md = require("markdown-it")();
// set custom container
for (let i = 1; i <= 5; i++ ) {
const [containerName, openingTag, closingTag ] = context.getCustomContainer(i);
if ( containerName ) {
if ( !openingTag && !closingTag) {
md.use(require('markdown-it-container'), containerName); // <div class="containerName"> ... </div>
} else {
md.use(require('markdown-it-container'), containerName, {
render: function (tokens : any, idx : number) {
if (tokens[idx].nesting === 1) {
// opening tag
return openingTag + '\n';
} else {
// closing tag
return closingTag + '\n';
}
}
});
}
}
}
postData["content"] = md.render(markdown.content);
この処理では5つのカスタムコンテナの設定を順次チェックしていきます。
設定で「name」が指定されている場合は、markdown-it-containerを有効にします。
このとき、「openingTag」と「closingTag」が未指定の場合は、markdown-it-containerのデフォルト設定を利用することになり、開始タグに「<div class=”カスタムコンテナの名前”>」・終了タグに「</dvi>」が利用されます。
一方、「openingTag」と「closingTag」が指定されている場合は、これらを開始タグ・終了タグに利用するような関数をmarkdown-it-containerのrenderオプションに指定します。
いま見直すと、「require(markdown-it-container
)」がちょっと冗長な気がしますが・・・
実行
ここまで紹介した修正を行った上で、拡張機能の実行(デバッグ)を行うと、「設定」→「拡張機能」→「WordPress Post Configuration」に「Custom Container」で設定項目がNo1~No5の5個現われます。
それぞれのCustom Containerの設定には「name」「openingTag」「closingTag」が指定できます。
私は、WordPressのテーマCocoonで利用可能な「information-box」「alert-box」「info-box」を使えるようにしています。
この状態で
::: information-box
追加情報1
:::
::: alert-box
注意事項
:::
::: info-box
追加情報2
:::
という記事を作成して投稿すると、
<div class="information-box">追加情報1</div>
<div class="alert-box">注意事項</div>
<div class="info-box">追加情報2</div>
というHTMLが生成されます。
プルリクエスト
GitHubでフォークしたプロジェクトは、オリジナルのプロジェクトに対して修正内容をプルリクエストという形で通知することができます。
今回の修正についてはまだプルリクエストを作成しておりません。
これは前々回の修正のプルリクエストが受け入れられるかどうか不明のためです。
前々回の修正のプルリクエストが受け入れられた場合は、今回の修正のプルリクエスト化をしたいと思います。
まとめ
今回もVS Code用の拡張機能であるWordPress Post拡張機能の修正したことを紹介しました。
今回の修正では、Markdownの任意のブロックをHTMLタグで挟むことができるカスタムコンテナ機能を追加しました。このカスタムコンテナ機能を使うとWordPressの記事をMarkdownで記述する際の表現力が上がるのではないかと思います。
次回はこれまでの修正を統合してパッケージ(VSIXファイル)を作成したいと思います。
コメント