キュレーションメディアの記事は、SNS で共有されて読まれることが多くなります。共有されたときにタイトルや画像がきちんと表示されるかどうかは、OGP(=SNS に「このページのタイトル・説明・画像はこれ」と伝える meta タグ)で決まります。また、アフィリエイトリンクなどの広告を含む記事では、2023年10月1日から、広告であることが分かる表示がこれまで以上に重要になりました。いわゆる「ステマ規制」です。
「SNS で共有したときの見た目を整えたい。あと、アフィリエイトの記事に PR 表記を入れたいけど、書き忘れが怖い…」
結論から言うと、OGP は記事の情報から自動で作り、PR 表記は「広告を含む」のチェックと広告リンクの検出の両方をきっかけに、プラグインで自動挿入するのが確実です。表記をテーマや書き手の手作業に任せると、テーマの変更や書き忘れで消えてしまいます。ただし、表記の文言や位置が法令上十分かどうかは、コードでは判断できません。社内で決め、必要に応じて専門家に確認してください。
前回の第8回では、目次と構造化データを作りました。第9回の今回は、OGP・X カードの出力と、広告・PR表記の仕組みをプラグインに追加します。
今回のゴールと、ステマ規制の概要
完成すると、次のようになります。
- 記事ページとトップページの
<head>に、OGP(og:title・og:description・og:image など)と X カードの meta タグが出る - 編集画面の「広告・PR表記」パネルで「この記事は広告を含む」をオンにすると、記事タイトルの直後に PR 表記が、記事一覧・ランキング・関連記事のタイトルの前に「PR」ラベルが出る
- 設定画面に登録した広告リンクのドメインへのリンクには
rel="sponsored"が付き、その記事はチェックを忘れていても PR 表記が出る
ステマ規制で何が求められているか
消費者庁のページでは、広告であるにもかかわらず広告であることを隠すことが「ステルスマーケティング」であり、令和5年10月1日から景品表示法違反になると説明されています。根拠は「一般消費者が事業者の表示であることを判別することが困難である表示」という告示(令和5年内閣府告示第19号)です。ポイントを整理すると次のとおりです。
- 規制されるのは、広告であって、一般消費者が広告であることを分からないもの
- 広告には、企業がインフルエンサーなどの第三者に依頼・指示するものも含まれる。アフィリエイトプログラムを使った表示も、運用基準の中で例として挙げられている
- 規制の対象は、商品・サービスを供給する事業者(広告主)
📰 出典:消費者庁「令和5年10月1日からステルスマーケティングは景品表示法違反となります。」
規制の対象は広告主ですが、メディア側が表記をしなければ、広告主はメディアに広告を出せません。また、読者から見れば「広告なのに隠していた」メディアとして信頼を失います。キュレーションメディアにとって、PR 表記は運営の前提と考えておくのが安全です。
運用基準から読み取れる「実装で気をつけること」
告示の運用基準には、広告であることが明瞭になっていない例と、明瞭になっている例が挙げられています。そのうち、画面の作り方に関わるものを抜き出すと次のとおりです。
| 運用基準で挙げられている例 | 今回の実装での対応 |
|---|---|
| 「広告」「宣伝」「プロモーション」「PR」といった文言による表示は、明瞭になっている例 | 記事では「【広告】」で始まる文章、一覧では「PR」ラベルを表示 |
| 視認しにくい末尾の位置にだけ表示する例は、明瞭になっていない | 記事タイトルの直後(本文より前)に表示 |
| 周囲の文字より小さい、薄い色で認識しにくい例は、明瞭になっていない | 本文と同じ文字サイズ・太字、背景色と枠線付き。色は第1回でコントラスト比を確認した「注意・PR表記」の色 |
| 他の情報に紛れ込ませる例は、明瞭になっていない | 独立した枠として表示し、ほかの注記とまとめない |
📰 出典:消費者庁「「一般消費者が事業者の表示であることを判別することが困難である表示」の運用基準」
運用基準には「これらの文言を使っていても、表示内容全体から明瞭と認められない場合もある」という注意も書かれています。文言を入れれば必ず適法、というものではありません。個別の記事の判断は、社内のルールと専門家への確認で行ってください。
今回追加・変更したファイル
| ファイル | 内容 |
|---|---|
プラグイン includes/ogp.php | OGP・X カードの meta タグ出力(新規) |
プラグイン includes/pr-notice.php | 投稿メタ「広告を含む」、広告リンクのドメイン設定、PR 表記と rel=”sponsored”(新規) |
プラグイン editor/pr-panel.js・webpack.config.js | 編集画面の「広告・PR表記」パネル(新規)とビルド対象への追加 |
プラグイン assets/pr-notice.css | PR 表記の見た目(新規) |
プラグイン blocks/ranking/render.php・blocks/related/render.php | 一覧に「PR」ラベルを追加 |
プラグイン curation-tools.php | 読み込み、バージョン 0.9.0 |
企画の段階ではテーマに PR 表記のパターン(patterns/pr-notice.php)を置く予定でしたが、表記はテーマを替えても消えてはいけないため、表示も CSS もプラグイン側に置きました。今回、テーマの変更はありません。
OGP と X カードを記事の情報から作る
wp-content/plugins/curation-tools/includes/ogp.php(curation_tools_print_ogp() の抜粋。出力を止めるフィルターの判定と、トップページ用の配列の中身を省略)
if ( is_singular( 'post' ) ) {
$post = get_queried_object();
if ( ! $post instanceof WP_Post ) {
return;
}
$tags = array(
'og:type' => 'article',
'og:title' => curation_tools_plain_text( get_the_title( $post ) ),
'og:description' => curation_tools_get_description( $post ),
'og:url' => get_permalink( $post ),
);
} elseif ( is_front_page() ) {
// トップページは og:type を website にし、サイト名とキャッチフレーズを使う
}
// (中略: og:site_name・og:locale・og:image・公開日と更新日を追加)
// 横長の画像があれば大きい画像のカード、なければ小さいカードにする。
$large = $image && $image['width'] >= 600 && $image['width'] > $image['height'];
echo '<meta name="twitter:card" content="' . esc_attr( $large ? 'summary_large_image' : 'summary' ) . '" />' . "\n";
foreach ( $tags as $property => $content ) {
if ( '' === $content ) {
continue;
}
$value = in_array( $property, array( 'og:url', 'og:image' ), true ) ? esc_url( $content ) : esc_attr( $content );
printf( '<meta property="%1$s" content="%2$s" />' . "\n", esc_attr( $property ), $value );
}
OGP の基本となるプロパティは og:title・og:type・og:image・og:url の4つです。これに説明文(og:description)とサイト名(og:site_name)を加えています。
X(旧 Twitter)のカードは、twitter:card でカードの種類を指定し、タイトルや画像は og: のタグがあればそれが使われます。そこで X 専用のタグは twitter:card だけにして、二重管理を避けました。
📰 出典:X Developer Platform「Cards markup」
説明文と画像のフォールバック(代わりに使うもの)
- 説明文:手動の抜粋があればそれを使い、なければ本文の先頭から120文字で作ります。
get_the_excerpt()は本文の表示用の処理を通るため使わず、excerpt_remove_blocks()で文章系のブロックだけを残してから、タグを除いて切り詰めています。 - パスワード保護の記事:本文の内容が SNS に漏れないよう、説明文を空にします。
- 画像:アイキャッチがあればその large サイズ、なければ「サイトアイコン」(ブラウザのタブなどに表示される、サイトの正方形の画像)を使います。どちらもなければ画像のタグは出しません。
includes/ogp.php(curation_tools_get_description() の抜粋)
if ( post_password_required( $post ) ) {
return '';
}
$text = has_excerpt( $post ) ? $post->post_excerpt : excerpt_remove_blocks( $post->post_content );
$text = curation_tools_plain_text( strip_shortcodes( $text ) );
$text = trim( preg_replace( '/\s+/u', ' ', $text ) );
if ( mb_strlen( $text ) > $length ) {
$text = mb_substr( $text, 0, $length - 1 ) . '…';
}
return $text;
SEO 系のプラグインを入れると、同じ OGP が二重に出力されることがあります。その場合は、フィルター curation_tools_output_ogp で false を返すと、このプラグインの出力を止められるようにしました。
「広告を含む」の設定と、広告リンクの自動検出
PR 表記を出すかどうかは、次の2つで判断します。
| きっかけ | 設定する場所 | 目的 |
|---|---|---|
投稿メタ _curation_has_ad | 編集画面の「広告・PR表記」パネル | 書き手・編集者が明示的に「広告を含む」と宣言する |
| 本文に広告リンクがある | 設定 > 表示設定「広告リンクのドメイン」 | チェックの付け忘れがあっても表記が出るようにする |
投稿メタは第6回の監修者と同じく register_post_meta() で登録し、auth_callback で「その投稿を編集できる人だけが変更できる」ようにしています。
includes/pr-notice.php(curation_tools_post_has_ad() の抜粋)
$has_ad = (bool) get_post_meta( $post_id, '_curation_has_ad', true );
$hosts = (array) get_option( 'curation_tools_sponsored_hosts', array() );
if ( ! $has_ad && $hosts ) {
$processor = new WP_HTML_Tag_Processor( (string) get_post_field( 'post_content', $post_id ) );
while ( $processor->next_tag( 'A' ) ) {
$href = $processor->get_attribute( 'href' );
if ( is_string( $href ) && curation_tools_is_sponsored_url( $href, $hosts ) ) {
$has_ad = true;
break;
}
}
}
広告リンクのドメインは、register_setting() で表示設定のページに入力欄を追加しました。保存は WordPress の設定 API が行うため、nonce(=正規の画面から送信されたことの確認)と管理者権限(manage_options)の確認は WordPress に任せられます。入力値は sanitize_callback で「小文字のホスト名だけ」に整えます(https:// やパスは取り除き、使えない文字を含む行は捨てる)。
📰 出典:WordPress Developer Resources「register_setting()」
PR 表記をタイトルの直後と一覧に出す
表記は、記事タイトル(post-title ブロック)の表示に render_block_core/post-title フィルターで追加します。第3回で作った3種類の記事テンプレートすべてでタイトルは post-title ブロックなので、テンプレートを1つずつ直す必要がありません。
includes/pr-notice.php(curation_tools_add_pr_notice_to_title() の抜粋)
$post_id = isset( $instance->context['postId'] ) ? (int) $instance->context['postId'] : 0;
if ( ! $post_id || 'post' !== get_post_type( $post_id ) || ! curation_tools_post_has_ad( $post_id ) ) {
return $content;
}
wp_enqueue_style( 'curation-tools-pr-notice' );
// 表示中の記事そのもののタイトルなら文章の表記、それ以外(一覧の中のタイトル)なら「PR」ラベル。
if ( is_singular( 'post' ) && get_queried_object_id() === $post_id ) {
return $content . '<p class="curation-pr-notice" role="note">' . esc_html( curation_tools_pr_notice_text() ) . '</p>';
}
return '<p class="curation-pr-label">PR</p>' . $content;
表記の文言は既定で「【広告】この記事にはアフィリエイトリンクなどの広告が含まれます。リンク先で商品・サービスを申し込むと、当サイトが報酬を受け取ることがあります。」とし、フィルター curation_tools_pr_notice_text で変更できます。文言は社内で決めて差し替えてください。
CSS はプラグインの assets/pr-notice.css に置き、PR 表記を出すページでだけ読み込みます。色はテーマの「注意・PR表記」の色(第1回)を使い、テーマにその色がない場合でも既定の色で表示されるようにしています。
広告リンクに rel=”sponsored” を付ける
Google は、広告や有料のリンクに rel="sponsored" を付けることを推奨しています。本文の表示時に、登録したドメインへのリンクにだけ sponsored(と noopener)を追加します。書き手が付けた nofollow などの既存の値は残します。
📰 出典:Google 検索セントラル「外部リンクの rel 属性(nofollow/ugc/sponsored)」
動作確認の方法
第0回・第2回の手順の後、プラグインをビルドしてから確認しました(筆者の環境で確認済みです)。
# OGP と X カードの meta タグを確認する
curl -s http://localhost:8088/<記事のスラッグ>/ | grep -E 'og:(title|description|image|url|type)|twitter:card'
# 記事に「広告を含む」を設定する(編集画面のパネルと同じ)
docker compose run --rm wpcli wp post meta update <記事ID> _curation_has_ad 1
- アイキャッチ(横長)のある記事は
summary_large_image、ない記事はsummary。説明文は抜粋または本文の先頭から作られる - パスワード保護の記事は og:description が出ない。タイトルに
"や&を含む記事でも属性値が正しくエスケープされる - 「広告を含む」をオンにした記事でだけ、タイトルの直後に PR 表記が出る。トップページ・特集ページの一覧、ランキング・関連記事では、その記事のタイトルの前に「PR」ラベルが出る
- 広告リンクのドメインを登録すると、本文中の該当リンクが
rel="nofollow sponsored noopener"になり、チェックがオフの記事でも PR 表記が出る。ほかのドメインへのリンクは変わらない - 表示設定の入力欄に
https://Aff2.Example.NET/pathや不正な文字列を入れて保存すると、aff2.example.netだけが保存される - 編集画面の「広告・PR表記」パネルでスイッチをオンにして保存すると、投稿メタが保存される(ヘッドレスブラウザで確認)
- 寄稿者のアカウント(アプリケーションパスワード)で、他人の記事の「広告を含む」を REST API から変えようとすると 403 になる
実際の SNS(X・Facebook など)に URL を貼ったときのカード表示は、ローカル環境では確認できないため、公開環境の URL で確認してください。SNS 側はカードの情報をキャッシュするため、OGP を直しても表示がすぐ変わらないことがあります。
つまずきやすい点・セキュリティ上の注意
- 表記をテーマに置かない:テーマのテンプレートに表記を書くと、テーマの変更やテンプレートの編集で消えてしまいます。法令や信頼に関わる表示は、機能としてプラグインに置きましょう。
- 「広告を含む」の判断基準を決める:アフィリエイトリンクだけでなく、広告主から商品の提供を受けた紹介や、依頼を受けて書いた記事も対象になり得ます。どの場合にオンにするかを編集ルールに書いておきます。
- ドメインの登録漏れ:自動検出は登録したドメインにしか効きません。短縮 URL や計測用のリダイレクト URL を使う広告は検出できないため、チェックの運用と併用します。
- OGP の二重出力:SEO プラグインと併用する場合は、どちらか一方にします。
発注者向けメモ:PR 表記は「文言」「位置」「付け忘れ防止」を要件にする
ステマ規制への対応は、法務の判断と画面の実装の両方が必要です。開発会社に依頼するときは、次の点を要件として書いておきましょう。
- 文言:記事の表記と一覧のラベルの文言。社内(必要に応じて専門家)で決めたものを渡す
- 位置と見た目:本文より前に、本文と同じ大きさで、背景色などで区別して表示する
- 付け忘れ防止:チェックの仕組みに加えて、広告リンクの自動検出や公開前のレビュー(第11回で扱います)を組み合わせる
- テーマ変更への耐性:テーマを替えても表記が残る作りになっているか
工数が増えるのは、広告の種類ごとに文言を変えたい場合、外部の広告配信サービスのタグを扱う場合、過去記事をまとめて見直す場合です。
打ち合わせでは、次のように聞いてみてください。
- 「PR 表記は、テーマを変更しても表示されますか? どこで出力していますか?」
- 「書き手が『広告を含む』のチェックを忘れた場合、どうやって気づけますか?」
- 「SNS で共有したときのタイトル・画像は、記事ごとにどこから取られますか? 画像がない記事ではどうなりますか?」
まとめと次回予告
第9回では、OGP・X カードと広告・PR表記を作りました。
- OGP は記事のタイトル・抜粋・アイキャッチから自動で作り、パスワード保護の記事では説明文を出さない
- PR 表記は、投稿メタのチェックと広告リンクの自動検出の両方をきっかけに、タイトルの直後と一覧に出す
- 表記は本文と同じ大きさで、本文より前に、区別できる見た目で表示する(消費者庁の運用基準の例を参考にした)
- 広告リンクには
rel="sponsored"を付ける - 文言や位置が法令上十分かの判断は、コードではなく社内のルールと専門家への確認で行う
次回は「表示速度の改善 ― 画像サイズ・キャッシュ・計測」です。画像サイズの整理、キャッシュの設定と、改善前後の計測方法を扱います。
この連載の記事一覧
この記事は連載「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件)
[…] 前回の第9回では、OGP と広告・PR表記を作りました。第10回の今回は、画像サイズの整理、ブラウザキャッシュの設定、改善前後の計測を行います。 […]