背景
VSCodeでMarkdownを書いてnpm run publish一発でWordPressに投稿するシステムを作る中で、Markdown記法がそのまま画面に表示されてしまう問題にぶつかりました。原因と解決策をまとめます。
1. 基本構成:REST APIへのPOSTだけならシンプル
const marked = require('marked');
const matter = require('gray-matter');
const axios = require('axios');
const { data: frontMatter, content: markdown } = matter(fileContent);
const htmlContent = marked(markdown);
await axios.post(
`${WP_URL}/wp-json/wp/v2/posts`,
{ title: frontMatter.title, content: htmlContent, slug: frontMatter.slug, status: 'draft' },
{ auth: { username: WP_USER, password: WP_APP_PASSWORD } }
);
markedでMarkdown→HTML変換してから送るHTMLモードは、この時点で問題なく動きます。
2. WP Githuber MDでMarkdownをそのまま保存したい場合の落とし穴
HTML変換を挟まず、Markdownをそのまま送ってWordPress側でもMarkdown編集を続けたい場合、WP Githuber MDプラグインを使います。しかし単にMarkdown文字列をcontentに入れて送るだけでは、以下のように記号がそのまま表示されてしまいます。
<p># タイトル</p>
<p>## 見出し</p>
原因: WordPress REST APIはデフォルトでMarkdownを認識しません。Githuber MD側に「この記事はMarkdownである」と伝えるメタフィールドが必要でした。
解決策:
const postData = {
title: frontMatter.title,
content: markdown, // HTML変換せずMarkdownのまま
meta: {
_is_githuber_markdown: '1',
_is_githuber_markdown_enabled: 'yes'
}
};
このメタフィールドを付けることで、Githuber MD側がMarkdownとして正しく解釈するようになりました。
3. 既存記事がHTMLの場合はMarkdownを送っても効かない
一度HTMLとして保存された記事に対してMarkdownを送信しても、Githuber MD側はそれをテキストとして扱うため、<p>## 見出し</p>のように壊れます。記事ごとに「HTMLモード」か「Markdownモード」かをFront Matterで明示的に切り替える設計にして解決しました。
# HTMLモード(推奨・デフォルト)
mode: html
→ スクリプト側でHTML変換 → Gutenbergエディタ
# Markdownモード
mode: markdown
→ Markdownをそのまま送信 → WP Githuber MDエディタ
4. 既存記事の自動判定(新規作成 or 更新)
スラッグで既存記事を検索し、あれば更新、なければ新規作成に振り分けます。
const existingPost = await findExistingPost(frontMatter.slug);
if (existingPost) {
await axios.post(`${WP_URL}/wp-json/wp/v2/posts/${existingPost.id}`, data, authHeader);
} else {
await axios.post(`${WP_URL}/wp-json/wp/v2/posts`, data, authHeader);
}
5. タイトル重複を自動回避
Markdown本文の先頭に# タイトルを書く習慣があると、WordPressのタイトルフィールドと二重表示されてしまいます。HTMLモードでは、変換前に最初のH1だけを機械的に取り除く処理を挟んでいます。
function removeFirstH1(markdown) {
const lines = markdown.split('\n');
let found = false;
return lines.filter(line => {
if (!found && line.trim().startsWith('# ') && !line.trim().startsWith('## ')) {
found = true;
return false;
}
return true;
}).join('\n');
}
まとめ
「Markdownがそのまま表示される」問題は、プラグイン側にMarkdownであることを伝えるメタフィールドの有無が原因でした。画像アップロードの重複問題(ハッシュベースでの解決)は別記事にまとめています。