キュレーションメディアでは、公式発表や公的資料の一文を引用して解説する場面が日常的にあります。そのたびに「出典を書き忘れた」「どこからの引用か分からない」「いつ確認した情報か不明」といった記事が混ざると、サイト全体の信頼を損ないます。
「引用するときに出典の書き忘れが起きないよう、WordPress の入力画面の側で防げない?」
結論から言うと、引用文・出典名・出典URL・確認日をセットで入力する独自ブロック(引用元カード)を作り、未入力の項目があればエディター上で警告するのが効果的です。WordPress 6.8 では、block.json と PHP の表示処理(render.php)を中心にした「動的ブロック」として、小さなプラグインで実装できます。
前回の第3回では、記事・まとめ・ランキングのテンプレートとパターンを作りました。第4回の今回は、引用の「出所の明示」を仕組みで支える引用元カードブロックを作ります。
今回のゴール:引用の書き忘れを入力画面で防ぐ
完成すると、次のように動きます。
- エディターの「ブロックを追加」から「引用元カード」を挿入し、本文に引用文、右側の設定欄に出典名・出典URL・確認日を入力する
- どれかが未入力、または URL が http/https で始まっていない場合、ブロックの上部に警告が表示される
- 公開ページでは、引用文が
<blockquote>(=引用であることを示す HTML の要素)で囲まれ、その下に「出典:出典名(リンク)(確認日:2025年7月10日)」が表示される - 引用文か出典名が空のままなら、公開ページにはカード自体を表示しない
引用の要件と、ブロックで支えられる範囲
著作権法第32条は、公表された著作物は引用して利用できるとしたうえで、その引用は「公正な慣行に合致するもの」で、「報道、批評、研究その他の引用の目的上正当な範囲内」で行わなければならないと定めています。また第48条は、引用する場合に出所を「その複製又は利用の態様に応じ合理的と認められる方法及び程度により」明示することを求めています。
📰 出典:e-Gov法令検索 著作権法(第32条・第48条)
文化庁の著作権テキストでは、引用の条件の例として、必然性があること、引用部分が明確に区別されていること、自分の文章と引用部分の主従関係が明確であること、出所を明示することなどが挙げられています(第0回でも紹介しました)。
📰 出典:文化庁「著作権テキスト(令和6年度版)」
このうち、ブロックという仕組みで支えられるのは一部だけです。
| 引用の条件(一般に挙げられるもの) | 引用元カードで支えられるか |
|---|---|
| 引用部分が明確に区別されている | 支えられる:カードの枠と <blockquote> で本文と見た目・HTML の両方で区別する |
| 出所の明示 | 支えられる:出典名・URL・確認日を入力欄にし、未入力なら警告・非表示にする |
| 引用の必然性 | 支えられない:なぜその文章を引用するのかは、書き手と編集者が判断する |
| 主従関係(自分の文章が主) | 支えられない:本文の量と内容で決まる。レビューで確認する |
ブロックは「出典の書き忘れ」を防ぐ道具であり、引用が適法かどうかを判断するものではありません。個別の記事の判断に迷う場合は、弁護士などの専門家に確認してください。
引用元カードの仕組み:動的ブロックにする理由
WordPress のブロックには、大きく分けて2種類の作り方があります。
| 種類 | 保存されるもの | 表示の作られ方 | 向いている用途 |
|---|---|---|---|
| 静的ブロック | 完成した HTML | 保存時の HTML をそのまま表示 | 見た目が変わらない装飾 |
| 動的ブロック | 入力値(属性)だけ | 表示のたびに PHP(render.php)で HTML を作る | 表示ルールを後から変えたいもの、値の検証が必要なもの |
引用元カードは動的ブロックにしました。理由は次の3つです。
- 表示ルールを後から変えても全記事に反映される:たとえば「確認日の表示形式を変える」「出典の前に著者名も出す」といった変更が、既存記事を1本ずつ直さずに済む
- 出力の直前に値を検証できる:URL が
javascript:のような危険な形式なら出さない、といった処理を PHP で確実に行える - 表示を PHP で書ける:JavaScript のビルドはエディター画面用だけで済み、公開ページの表示はテーマ開発と同じ PHP の知識で保守できる
📰 出典:Block Editor Handbook「Static or Dynamic rendering of a block」
今回追加・変更したファイル
すべてプラグイン wp-content/plugins/curation-tools/ 配下です。
| ファイル | 内容 |
|---|---|
package.json | @wordpress/scripts でエディター用 JS をビルドする設定(新規) |
blocks/source-card/block.json | ブロックの名前・属性・読み込むファイルの定義(新規) |
blocks/source-card/index.js | ブロックの登録(新規) |
blocks/source-card/edit.js | エディターでの表示・入力欄・警告(新規) |
blocks/source-card/render.php | 公開ページの HTML を作る処理(新規) |
blocks/source-card/style.css | カードの見た目(新規) |
curation-tools.php | ビルド結果のブロックを登録、バージョン 0.4.0 |
blocks/ がソース、npm run build で作られる build/ が WordPress に読み込ませるファイルです。build/ と node_modules/ は Git で管理しません。
block.json でブロックの項目を定義する
block.json は、ブロックの「設計書」にあたるファイルです。名前・表示名・入力項目(属性)と、エディター用 JS・CSS・PHP のどれを読み込むかを書きます。
blocks/source-card/block.json
{
"$schema": "https://schemas.wp.org/wp/6.8/block.json",
"apiVersion": 3,
"name": "curation-tools/source-card",
"version": "0.4.0",
"title": "引用元カード",
"category": "text",
"icon": "format-quote",
"description": "他のサイトや資料の文章を引用するときに使う。引用文・出典名・出典URL・確認日をセットで表示する。",
"keywords": [ "引用", "出典", "quote" ],
"textdomain": "curation-tools",
"attributes": {
"quote": { "type": "string", "default": "" },
"sourceTitle": { "type": "string", "default": "" },
"url": { "type": "string", "default": "" },
"checkedDate": { "type": "string", "default": "" }
},
"supports": {
"html": false,
"reusable": false
},
"editorScript": "file:./index.js",
"style": "file:./style-index.css",
"render": "file:./render.php"
}
(example の項目は省略しています。実ファイルを参照してください)
ポイントは次のとおりです。
apiVersion: 3:WordPress 6.8 時点の最新の形式です。記事に使われるブロックがすべてこの形式なら、エディターの本文部分が iframe(=独立した画面領域)で表示され、テーマの CSS が公開ページに近い形で反映されます。attributes:入力項目です。動的ブロックでは、これらの値だけが本文にコメントの形で保存されます。render:公開ページの表示に使う PHP ファイルを指定します。これがあると動的ブロックとして扱われます。supports.html: false:「HTML として編集」を使えないようにし、入力欄以外から値を変えられないようにしています。
📰 出典:Block Editor Handbook「Metadata in block.json」
edit.js:エディターに入力欄と警告を出す
エディター画面での見た目と入力欄を作るのが edit.js です。引用文はカードの中に直接入力し、出典名・URL・確認日は右側の設定パネル(InspectorControls)に置きました。
blocks/source-card/edit.js(抜粋)
function getProblems( attributes ) {
const { quote, sourceTitle, url, checkedDate } = attributes;
const problems = [];
if ( ! quote.trim() ) {
problems.push( '引用文' );
}
if ( ! sourceTitle.trim() ) {
problems.push( '出典名' );
}
if ( ! /^https?:\/\/\S+$/.test( url.trim() ) ) {
problems.push( '出典URL(http:// または https:// で始まるURL)' );
}
if ( ! /^\d{4}-\d{2}-\d{2}$/.test( checkedDate ) ) {
problems.push( '確認日' );
}
return problems;
}
<figure { ...blockProps }>
{ problems.length > 0 && (
<Notice status="warning" isDismissible={ false }>
{ '次の項目を入力してください:' +
problems.join( '、' ) +
'。引用文・出典名が空のままだと、公開ページにこのカードは表示されません。' }
</Notice>
) }
<blockquote className="curation-source-card__quote">
<RichText
tagName="p"
value={ quote }
onChange={ ( value ) => setAttributes( { quote: value } ) }
allowedFormats={ [] }
placeholder="引用する文章を、原文どおりに貼り付けます(要約や言い換えは引用ではなく本文に書く)"
/>
</blockquote>
<figcaption className="curation-source-card__source">
{ '出典:' + ( sourceTitle || '(出典名が未入力)' ) }
{ checkedDate && '(確認日:' + checkedDate + ')' }
</figcaption>
</figure>
工夫した点は次のとおりです。
- 警告は閉じられない(
isDismissible={ false }):入力が揃うまで表示し続け、揃った時点で自動的に消えます。 - 引用文に太字などの書式を付けられない(
allowedFormats={ [] }):原文にない強調を加えると、引用元の意図と違って読まれるおそれがあるためです。改行だけは使えます。 - 確認日は日付入力欄(
TextControlのtype="date"):ブラウザの日付選択が使え、値は2025-07-10の形式で保存されます。 - placeholder で使い方を案内:「要約や言い換えは引用ではなく本文に書く」と入力欄そのものに書き、引用と自分の文章を分ける意識を促します。
なお、この警告は「保存・公開を止める」ものではありません。下書き保存まで止めると書きかけの記事が保存できなくなるためです。公開前に人がチェックする工程は第11回で扱います。
render.php:公開ページの HTML を安全に出力する
公開ページの表示は render.php で作ります。WordPress から $attributes(入力値)が渡されるので、検証とエスケープ(=HTML として解釈されないよう特殊文字を変換すること)をしてから出力します。
blocks/source-card/render.php(冒頭のコメントを省略)
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$curation_quote = isset( $attributes['quote'] ) ? trim( (string) $attributes['quote'] ) : '';
$curation_source_title = isset( $attributes['sourceTitle'] ) ? trim( (string) $attributes['sourceTitle'] ) : '';
if ( '' === wp_strip_all_tags( $curation_quote ) || '' === $curation_source_title ) {
return;
}
// http / https 以外(javascript: など)は空文字になり、リンクも cite 属性も出さない。
$curation_url = isset( $attributes['url'] ) ? esc_url( (string) $attributes['url'], array( 'http', 'https' ) ) : '';
// 確認日は YYYY-MM-DD のみ受け付け、サイトの日付形式で表示する。
$curation_checked = '';
$curation_date = isset( $attributes['checkedDate'] )
? DateTimeImmutable::createFromFormat( '!Y-m-d', (string) $attributes['checkedDate'], new DateTimeZone( 'UTC' ) )
: false;
if ( $curation_date && $curation_date->format( 'Y-m-d' ) === $attributes['checkedDate'] ) {
$curation_checked = sprintf(
'<time datetime="%1$s">%2$s</time>',
esc_attr( $curation_date->format( 'Y-m-d' ) ),
esc_html( wp_date( get_option( 'date_format' ), $curation_date->getTimestamp(), new DateTimeZone( 'UTC' ) ) )
);
}
// 引用文はエディターで書式を付けられない設定。改行(br)だけを許可する。
$curation_quote_html = wp_kses( $curation_quote, array( 'br' => array() ) );
$curation_source_html = esc_html( $curation_source_title );
if ( '' !== $curation_url ) {
$curation_source_html = sprintf(
'<a href="%1$s" rel="noopener">%2$s</a>',
esc_url( $curation_url ),
$curation_source_html
);
}
?>
<figure <?php echo get_block_wrapper_attributes( array( 'class' => 'curation-source-card' ) ); ?>>
<blockquote class="curation-source-card__quote"<?php echo '' !== $curation_url ? ' cite="' . esc_url( $curation_url ) . '"' : ''; ?>>
<p><?php echo $curation_quote_html; ?></p>
</blockquote>
<figcaption class="curation-source-card__source">
出典:<cite><?php echo $curation_source_html; ?></cite>
<?php if ( '' !== $curation_checked ) : ?>
<span class="curation-source-card__checked">(確認日:<?php echo $curation_checked; ?>)</span>
<?php endif; ?>
</figcaption>
</figure>
(実ファイルでは、エスケープ済みであることを示す phpcs:ignore コメントを各 echo に付けています)
ここでのポイントは4つです。
- 引用文か出典名が空なら何も出さない:出所を示せない引用を公開しない、という編集方針をコードで守ります。
- URL は
esc_url()に許可するプロトコル(http / https)を渡す:javascript:などは空文字になり、リンクもcite属性も出力されません。 - 確認日は形式を厳密にチェック:
2025-13-40のような存在しない日付は表示しません。表示はサイトの設定(第0回で「Y年n月j日」に設定)に従います。 - HTML の構造:
<figure>の中に<blockquote cite>(引用本文と引用元URL)と<figcaption>(出典の表示)を置き、出典名は<cite>で囲みます。見た目だけでなく HTML としても「ここが引用で、出典はこれ」と分かる構造です。
📰 出典:WordPress Developer Resources「esc_url()」
📰 出典:MDN Web Docs「blockquote: ブロック引用要素」
カードの見た目は style.css で付けています。背景は第1回で「引用元・補足の背景」として定義した accent-1、左の線は brand、出典・確認日の文字は accent-4 です。
blocks/source-card/style.css(抜粋)
.wp-block-curation-tools-source-card {
margin-inline: 0;
padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
background-color: var(--wp--preset--color--accent-1, #e8f0fb);
border-left: 4px solid var(--wp--preset--color--brand, #1a5fb4);
}
@wordpress/scripts でビルドしてプラグインに登録する
edit.js は JSX(=HTML に似た書き方ができる JavaScript の拡張)で書いているため、ブラウザで動く形に変換(ビルド)が必要です。WordPress 公式の開発ツール @wordpress/scripts を使います。
package.json(抜粋)
"engines": {
"node": ">=20.0.0"
},
"scripts": {
"build": "wp-scripts build --webpack-src-dir=blocks --output-path=build",
"start": "wp-scripts start --webpack-src-dir=blocks --output-path=build",
"lint:js": "wp-scripts lint-js blocks"
},
"devDependencies": {
"@wordpress/scripts": "30.16.0"
}
- バージョンは固定する:
^30.16.0のような範囲指定にすると、インストールする日によって違うバージョンが入り、ビルド結果が変わることがあります。package-lock.jsonも一緒に管理します。 - ソースの場所を指定する:既定では
src/を読むため、--webpack-src-dir=blocksでblocks/を指定しています。 - Node.js のバージョン:@wordpress/scripts 30 系は Node.js 18.12 以上を要件にしていますが、Node.js 18 は2025年4月でサポートが終了しています。執筆時点(2025年7月)の LTS(長期サポート版)である Node.js 20 か 22 を使ってください。筆者は Docker の node イメージ(20 と 22)のどちらでもビルドが成功することを確認しました。
📰 出典:Block Editor Handbook「@wordpress/scripts」
📰 出典:Node.js「Node.js Releases」
PC に Node.js を入れなくても、Docker でビルドできます(プラグインのフォルダで実行)。
docker run --rm -u "$(id -u):$(id -g)" -e HOME=/tmp -v "$PWD":/app -w /app node:22-bookworm \
sh -c 'npm ci && npm run build'
ビルドすると build/source-card/ に block.json・index.js・index.asset.php(エディター用 JS が依存する WordPress のスクリプト一覧)・style-index.css・render.php が出力されます。プラグイン本体では、この build/ の block.json を読み込むだけです。
curation-tools.php(追加部分)
/**
* ブロックを登録する。
*
* build/ は blocks/ を npm run build(@wordpress/scripts)でビルドした結果。
* block.json を読み込むだけで、エディター用 JS・CSS・render.php の登録まで行われる。
*/
function curation_tools_register_blocks() {
register_block_type( CURATION_TOOLS_DIR . 'build/source-card' );
}
add_action( 'init', 'curation_tools_register_blocks' );
📰 出典:WordPress Developer Resources「register_block_type()」
動作確認の方法
第0回・第2回の手順(setup.sh・seed-terms.sh)の後に、プラグインをビルドしてから確認します。以下はすべて筆者の環境で確認済みです。
# ブロックが登録されているか(REST API は投稿の編集権限が必要。アプリケーションパスワードで認証)
docker compose run --rm wpcli wp user application-password create admin verify --porcelain
curl -s -o /dev/null -w '%{http_code}\n' -u 'admin:<表示されたパスワード>' \
http://localhost:8088/wp-json/wp/v2/block-types/curation-tools/source-card
# 引用元カードを含む記事を作って HTML を確認する
echo '<!-- wp:curation-tools/source-card {"quote":"引用する文章です。","sourceTitle":"出典名","url":"https://example.com/","checkedDate":"2025-07-10"} /-->' \
| docker compose run --rm -T wpcli wp post create - --post_title=引用テスト --post_name=quote-test --post_status=publish
curl -s http://localhost:8088/quote-test/ | grep -A8 'curation-source-card'
確認できたことは次のとおりです。
npm run buildとnpm run lint:js(コーディング規約のチェック)が成功し、build/source-card/が生成される- REST API の block-types が 200 を返し、
is_dynamicが true、属性に quote・sourceTitle・url・checkedDate が含まれる(認証なしでは 401) - 公開ページに
<blockquote class="curation-source-card__quote" cite="https://example.com/">、出典リンク、<time datetime="2025-07-10">2025年7月10日</time>が出る - URL に
javascript:を入れた記事では、リンクとcite属性が出力されず、出典名だけが表示される。存在しない日付(2025-13-40)の確認日は表示されない - 出典名が空の記事では、カード自体が出力されない
- エディター(ヘッドレスブラウザで確認)でブロックを挿入すると、未入力の4項目を並べた警告が表示され、URL を
javascript:にすると URL の警告だけが残り、https の URL を入れると警告が消える
つまずきやすい点・セキュリティ上の注意
- build/ を本番に置き忘れる:
build/を Git で管理しない場合、本番へのデプロイ手順にnpm ci && npm run buildを入れる必要があります。逆に、本番サーバーにnode_modules/を置く必要はありません。どちらをどこで作るかを、デプロイ手順書に明記してください。 - 属性名を後から変えない:動的ブロックは属性だけを保存しているため、
sourceTitleを別の名前に変えると、既存記事の値が読めなくなります。 - エスケープは出力の直前で:render.php の値は、入力画面を経由せず REST API や WP-CLI から直接書き込まれることもあります。エディター側でチェックしていても、PHP 側で必ず検証・エスケープします。
- 著者名の表示:著作権法第48条第2項では、出所の明示にあたって、原則として著作物に表示されている著作者名も示す必要があるとされています。出典名の欄に「著者名『書名』」「組織名『ページ名』」のように書く運用ルールを決めておくと安心です。
発注者向けメモ:引用のルールは「仕組み」と「人の判断」に分けて依頼する
引用元カードのような仕組みは、出典の書き忘れや、引用と本文の区別があいまいな記事を減らすのに役立ちます。ただし、引用が適法かどうか(必然性・主従関係など)は仕組みでは判定できず、最終的には人が判断します。
開発会社に依頼するときは、次の点を決めておきましょう。
- 必須にする項目:出典名・URL・確認日のほかに、著者名・発行日などを必須にするか
- 未入力時の扱い:警告だけにするか、公開できないようにするか(公開を止める場合は、レビュー工程との関係も含めて設計が必要)
- ビルドとデプロイの担当:エディター用 JS をビルドする環境(Node.js のバージョン)と、本番への反映手順を誰が管理するか
- 引用ルールの文書化:何を出典として認めるか、画像の引用をどう扱うかなど、編集部のルールを誰が作り、誰が確認するか
なお、出典情報を URL から自動取得する、既存記事の引用部分を一括でブロックに置き換える、画像の引用にも対応する、といった要望が加わると、外部通信・移行作業・権利確認の分だけ工数とリスクが増えます。
打ち合わせでは、次のように聞いてみてください。
- 「このブロックの表示を変えたとき、既存の記事にも反映されますか? 記事を1本ずつ直す必要はありますか?」
- 「ブロックのビルドに使う Node.js と @wordpress/scripts のバージョンは、どこに記録されていますか?」
- 「出典が未入力の記事を公開前に見つける方法はありますか?」
まとめと次回予告
第4回では、引用元カードブロックを作りました。
- 引用文・出典名・出典URL・確認日をセットで入力し、未入力ならエディターで警告する
- 表示は render.php で作る動的ブロックにし、表示ルールの変更が全記事に反映されるようにした
- URL は http / https だけを許可し、
<blockquote cite>と<figcaption>で引用であることを HTML でも示す - @wordpress/scripts はバージョンを固定し、Node.js は執筆時点の LTS を使う
- ブロックが支えるのは「出所の明示」と「明確な区別」まで。引用の必然性や主従関係は人が判断する
次回は「『まとめリスト』と『比較表』をパターンとブロックスタイルで作る」です。まとめ記事で使う番号付きリストと、スマートフォンでも読める比較表を、独自ブロックを作らずにパターンとブロックスタイルで用意します。
この連載の記事一覧
この記事は連載「WordPressで作るキュレーションメディア」の1回です。連載のほかの回は次のとおりです(連載の一覧ページ)。
- 【WordPressで作るキュレーションメディア 第0回】キュレーションメディアの要件と「低品質まとめ」の教訓 ― Docker で WordPress 6.8 の土台を作る
- 【WordPressで作るキュレーションメディア 第1回】theme.json でデザイントークンを定義する(子テーマの基本)
- 【WordPressで作るキュレーションメディア 第2回】カテゴリ・タグ・「特集」― タクソノミー設計
- 【WordPressで作るキュレーションメディア 第3回】記事・まとめ・ランキングのテンプレートとパターン
- 【WordPressで作るキュレーションメディア 第4回】「引用元カード」ブロック ― 著作権法第32条の引用を仕組みで守る(この記事)
- 【WordPressで作るキュレーションメディア 第5回】「まとめリスト」と「比較表」をパターンとブロックスタイルで作る
- 【WordPressで作るキュレーションメディア 第6回】著者・監修者プロフィールを表示する(E-E-A-T の考え方)
- 【WordPressで作るキュレーションメディア 第7回】人気記事ランキングと関連記事を小さなプラグインで作る
- 【WordPressで作るキュレーションメディア 第8回】目次と構造化データ(JSON-LD: Article / BreadcrumbList / ItemList)
- 【WordPressで作るキュレーションメディア 第9回】OGP・SNS カードと「広告・PR表記」― ステマ規制への対応
- 【WordPressで作るキュレーションメディア 第10回】表示速度の改善 ― 画像サイズ・キャッシュ・計測
- 【WordPressで作るキュレーションメディア 第11回】権限・編集フロー・運用 ― 下書きレビュー、バックアップ、更新










コメント
コメント一覧 (1件)
[…] 前回の第4回では、引用文と出典をセットで入力する「引用元カード」ブロックをプラグインに作りました。第5回の今回は、まとめ記事の本文で使う2つの部品を子テーマに追加します。 […]