2026年5月31日
2026年5月31日
WordPressにMicroformats2(h-card/h-entry/h-feed)を実装してIndieWebに対応する方法
WordPressをIndieWebに対応させる第一歩は、テンプレートのHTMLにMicroformats2のクラス(h-card・h-entry・h-feed)を付けて、「誰が・何を・いつ書いたか」を機械が読める形にすることです。この記事では、既存プラグインで済ませる方法と、子テーマで自分のテーマに直接クラスを付ける方法(クラシックテーマ・ブロックテーマの両方)を説明し、最後にパーサーで正しく読めているかを確認する手順まで扱います。
Microformats2とは何か、何のために付けるのか
Microformats2(以下mf2)は、HTMLの class 属性に決まった名前を付けるだけで、ページの意味を構造化する仕組みです。JSON-LDのように別のスクリプトを埋め込むのではなく、画面に表示されている要素そのものに意味を持たせるのが特徴です。
IndieWebの文脈では、mf2は次のような用途で使われます。
- Webmention:他サイトから言及(返信・いいね・引用)を受け取ったとき、相手のページのh-entryを解析して「誰がどんな反応をしたか」をコメントとして表示する
- IndieAuth:自分のドメインを身元として使うログインで、h-cardや
rel="me"リンクがプロフィール情報の手がかりになる - ソーシャルリーダー:h-feedを読み込み、RSSの代わりに購読する
検索エンジン向けの構造化データ(JSON-LD)とは目的が違います。GoogleのリッチリザルトはJSON-LD等のschema.orgを前提としているため、mf2を付けても検索結果の見た目は変わらないと考えてください。両方を併用しても衝突はしません。
使う主なクラスの整理
最低限押さえておきたいのは次の3種類のルート(h- で始まるクラス)と、その中のプロパティです。
| ルート | 意味 | 主なプロパティ |
|---|---|---|
| h-card | 人・組織 | p-name、u-url、u-photo、p-note、u-uid |
| h-entry | 1件の投稿 | p-name、e-content、p-summary、dt-published、dt-updated、u-url、p-author、p-category |
| h-feed | 投稿の一覧 | p-name、子要素としてh-entryを並べる |
接頭辞にも意味があります。p- はテキスト、u- はURL(href や src を読む)、dt- は日時(<time datetime> の値を読む)、e- は中身のHTMLを丸ごと取る、という区別です。日時を <div> に付けると表示用の文字列が読まれてしまうため、dt-published は <time> 要素に付けるのが基本です。
なお、WordPressコアの post_class() は昔のmicroformats(hAtom)由来の hentry クラスを出力します。mf2のパーサーは、同じ要素にmf2のルートクラスがあればmf2を優先して読むため、hentry を消す必要はありません。
まずはプラグインで済ませられるか確認する
IndieWeb対応はWordPressのコミュニティで長く取り組まれており、次のようなプラグインがWordPress.orgで公開されています(2026年10月現在)。
- IndieWeb:関連プラグインの案内と、
rel="me"やh-card表示の補助をまとめたもの - Webmention:Webmentionの送受信。受け取った言及の解析にはmf2が使われます
- IndieAuth:自分のサイトをIndieAuthのサーバーとして使う
- Post Kinds:返信・いいね・ブックマークなど投稿の「種類」を扱う
ただし、プラグインはテーマのテンプレートまでは書き換えません。h-entryやh-feedのクラスがテーマ側に無ければ、Webmentionを送っても相手側でうまく解析されないことがあります。プラグインの機能範囲や設定画面の表記はバージョンで変わるため、導入前に各プラグインの説明ページで最新の対応状況を確認してください。過去にmf2対応をうたっていたテーマや補助プラグインの中には更新が止まっているものもあるので、最終更新日と対応WordPressバージョンも見ておくと安全です。
以下では、テーマ側に自分でクラスを付ける方法を説明します。作業は子テーマで行い、本番の前にステージング環境で表示崩れがないか確認してください。
クラシックテーマ:テンプレートとpost_classに追記する
投稿一覧と各投稿にh-entryを付ける
各投稿のラッパー要素には、post_class フィルターで h-entry を追加するのが手軽です。テンプレートを書き換えずに済み、ブロックテーマの投稿テンプレートブロック(後述)にも同じクラスが反映されます。
<?php
// 子テーマの functions.php
add_filter( 'post_class', function ( $classes ) {
if ( ! is_admin() ) {
$classes[] = 'h-entry';
}
return $classes;
} );
個別投稿テンプレートでプロパティを付ける
タイトル・本文・日付・著者は、子テーマにコピーしたテンプレート(single.php や template-parts/content-single.php など、テーマによって名前は異なります)に直接クラスを書き足します。出力値はエスケープしておきます。
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<h1 class="p-name"><?php the_title(); ?></h1>
<p class="entry-meta">
<a class="u-url" href="<?php echo esc_url( get_permalink() ); ?>">
<time class="dt-published" datetime="<?php echo esc_attr( get_the_date( DATE_W3C ) ); ?>">
<?php echo esc_html( get_the_date() ); ?>
</time>
</a>
<span class="p-author h-card">
<a class="u-url p-name" href="<?php echo esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ); ?>">
<?php echo esc_html( get_the_author() ); ?>
</a>
</span>
</p>
<div class="e-content">
<?php the_content(); ?>
</div>
</article>
ポイントは、p-author と h-card を同じ要素に付けて「著者プロパティの値がh-cardである」と表すことです。日付は DATE_W3C 形式で datetime 属性に出しているため、表示形式を日本語にしていてもパーサーは正しい日時を読めます。
一覧ページをh-feedで囲む
トップページやアーカイブのループ全体を h-feed で囲みます。index.php や archive.php のループの外側に1つ要素を足すだけです。
<div class="h-feed">
<h1 class="p-name"><?php echo esc_html( get_bloginfo( 'name' ) ); ?></h1>
<?php while ( have_posts() ) : the_post(); ?>
<?php get_template_part( 'template-parts/content', get_post_type() ); ?>
<?php endwhile; ?>
</div>
h-feedの中に各h-entryが入っていれば、リーダーは一覧として読み込めます。
ブロックテーマ:render_blockでクラスを足す
ブロックテーマではテンプレートがブロックで組まれているため、PHPテンプレートを直接編集できません。各ブロックの「追加CSSクラス」欄に手で入力する方法もありますが、日付のように内部の <time> 要素へ付けたいクラスは指定できません。そこで、ブロック単位のフィルター render_block_{ブロック名} と、WordPress 6.2で追加された WP_HTML_Tag_Processor を使ってHTMLにクラスを差し込みます。
<?php
// 子テーマの functions.php(ブロックテーマ用)
// 投稿タイトル → p-name
add_filter( 'render_block_core/post-title', function ( $content ) {
$p = new WP_HTML_Tag_Processor( $content );
if ( $p->next_tag() ) {
$p->add_class( 'p-name' );
}
return $p->get_updated_html();
} );
// 投稿本文 → e-content
add_filter( 'render_block_core/post-content', function ( $content ) {
$p = new WP_HTML_Tag_Processor( $content );
if ( $p->next_tag() ) {
$p->add_class( 'e-content' );
}
return $p->get_updated_html();
} );
// 投稿日 → 内側の <time> に dt-published
add_filter( 'render_block_core/post-date', function ( $content ) {
$p = new WP_HTML_Tag_Processor( $content );
if ( $p->next_tag( 'time' ) ) {
$p->add_class( 'dt-published' );
}
return $p->get_updated_html();
} );
// 投稿者名 → p-author h-card
add_filter( 'render_block_core/post-author-name', function ( $content ) {
$p = new WP_HTML_Tag_Processor( $content );
if ( $p->next_tag() ) {
$p->add_class( 'p-author' );
$p->add_class( 'h-card' );
}
return $p->get_updated_html();
} );
// クエリーループ → h-feed
add_filter( 'render_block_core/query', function ( $content ) {
$p = new WP_HTML_Tag_Processor( $content );
if ( $p->next_tag() ) {
$p->add_class( 'h-feed' );
}
return $p->get_updated_html();
} );
投稿テンプレートブロックの各項目には post_class の結果が使われるため、前の節の h-entry を追加するフィルターも一緒に入れておきます。日付ブロックの「最終更新日を表示」設定を使っている箇所に dt-published を付けると意味がずれるので、テンプレート内で投稿日と更新日をどう表示しているかを確認してから適用してください。ブロックのHTML構造はWordPressのバージョンで変わることがあるため、アップデート後は後述の確認手順をもう一度実行するのがおすすめです。
サイトの代表h-cardとrel=”me”を用意する
IndieWebでは、トップページに「このサイトの持ち主は誰か」を示す代表h-cardを置くのが慣例です。u-url と u-uid にトップページのURLを入れ、SNSなど自分が管理する他のプロフィールへのリンクに rel="me" を付けます。
<?php
// ヘッダーやフッターのテンプレート、またはショートコード経由で出力
$site_url = home_url( '/' );
$icon = get_site_icon_url( 96 );
?>
<div class="h-card">
<?php if ( $icon ) : ?>
<img class="u-photo" src="<?php echo esc_url( $icon ); ?>" alt="" width="48" height="48">
<?php endif; ?>
<a class="p-name u-url u-uid" href="<?php echo esc_url( $site_url ); ?>" rel="me">
<?php echo esc_html( get_bloginfo( 'name' ) ); ?>
</a>
<p class="p-note"><?php echo esc_html( get_bloginfo( 'description' ) ); ?></p>
<a href="https://github.com/your-account" rel="me">GitHub</a>
</div>
rel="me" は相互リンクで本人確認に使われます。リンク先のプロフィール側にも自分のサイトのURLを載せておかないと、IndieAuthなどで同一人物と判断されません。また、画面に見えない要素にだけmf2を付ける「隠しマークアップ」は、表示内容とずれやすいため避けるのが一般的です。
正しく読めているかを確認する
付けたクラスが期待どおりに解析されるかは、mf2パーサーで確認します。
- 公開中(またはステージングで外部から見える)の個別投稿URLを用意する
- Microformats2のパーサー(php-mf2を使ったオンラインのパーサーや、microformats.io など)にURLを入力する
- 結果のJSONで
typeがh-entryになっているか、propertiesにname・content・published・authorがそろっているかを見る - トップページやアーカイブでも同様に、
h-feedのchildrenに各h-entryが並んでいるかを確認する
よくあるつまずきは次のとおりです。
- nameに本文全体が入る:h-entryに
p-nameが無いと、要素全体のテキストが名前として推測されます。タイトル要素にp-nameを付けてください - publishedが日本語の日付文字列になる:
dt-publishedが<time>以外に付いています - authorが文字列だけになる:
p-authorの要素にh-cardが付いていません - キャッシュで反映されない:ページキャッシュやCDNを使っている場合は、テンプレート変更後にキャッシュを削除してから確認します
Webmentionプラグインを使う場合は、自分の別の投稿から言及を送り、著者名とアイコンが表示されるかも試します。
まとめ
- mf2はHTMLのclass属性で投稿や人の情報を構造化する仕組みで、Webmention・IndieAuth・ソーシャルリーダーで使われます。検索結果の見た目を変えるものではありません
- 主要なクラスはh-card・h-entry・h-feedの3種類。日時は
<time>要素にdt-publishedを付けます - プラグインは送受信や認証を担いますが、テーマ側のクラス付けは別途必要です。作業は子テーマで、ステージングで確認してから本番へ
- クラシックテーマは
post_classとテンプレートへの追記、ブロックテーマはrender_block_{ブロック名}とWP_HTML_Tag_Processorで対応できます - 仕上げにmf2パーサーで解析結果を確認し、WordPressの更新後にも再確認します