共有しても、カードが出ない
管理しているサイトで、記事を SNS で共有したときの見え方を見直していたときのことです。SNS は、ページの head にある OGP のタグ(og:title や og:image など)を読んで、タイトルと画像の入ったカードを作ります。ところがこのサイトの head を見ると、OGP のタグがどのページにも出ていませんでした。
調べてみると、SEO のプラグイン(All in One SEO)にもテーマにも OGP を出す設定はあるのですが、どちらも OFF になっていました。設定を ON にする方法もありますが、本番の設定はそのままにしておきたかったので、テーマの中に OGP を出す小さな機能を作り、プラグインやテーマの設定が ON になったときは、そちらに任せる形にしました。
出すタグと、値の取り方
決めたことは、タイトル・ディスクリプション・URL を、SEO のプラグインが出している値とそろえることです。別に作ると、検索結果と SNS のカードでディスクリプションが違う、URL がずれる、といったことが起きやすくなります。
| タグ | 値 |
|---|---|
og:title |
SEO のプラグインの title(<title> と同じ) |
og:description |
SEO のプラグインの meta description と同じ |
og:url |
SEO のプラグインの canonical と同じ |
og:image |
アイキャッチ画像。なければサイト共通の画像(1200×630) |
og:type |
記事は article、トップや一覧は website |
twitter:card |
summary_large_image(大きな画像のカード) |
X 用には twitter:card だけを出し、タイトル・ディスクリプション・画像は og: の値を読んでもらう形にしています(X の公式の説明は、今回は確かめられていません)。共通の画像は、Facebook などでよく使われる 1200×630 の大きさで作りました。
作ったファイル
ファイルはテーマのフォルダの中の functions フォルダに置き、functions.php から require_once で読み込んでいます。実際のファイルから、カテゴリーの一覧の説明文など、このサイトの作りに合わせた部分を外して短くしたものが次のコードです。
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
define( 'MY_OGP_IMAGE', '/img/ogp-default.jpg' ); // 1200×630
define( 'MY_OGP_IMAGE_W', 1200 );
define( 'MY_OGP_IMAGE_H', 630 );
// テーマに OGP を出す設定があるなら、それが ON かを返す(テーマに合わせて書き換える)
function my_ogp_theme_outputs() {
return false;
}
// All in One SEO のソーシャルの出力が ON か(array( og, twitter ))
function my_ogp_aioseo_social() {
if ( ! function_exists( 'aioseo' ) ) {
return array( false, false );
}
try {
return array(
(bool) aioseo()->options->social->facebook->general->enable,
(bool) aioseo()->options->social->twitter->general->enable,
);
} catch ( \Throwable $e ) {
return array( false, false );
}
}
function my_ogp_clean( $text ) {
$text = html_entity_decode( wp_strip_all_tags( (string) $text ), ENT_QUOTES, 'UTF-8' );
return trim( preg_replace( '/\s+/u', ' ', $text ) );
}
// <title> と同じ
function my_ogp_title() {
$title = function_exists( 'aioseo' ) ? (string) aioseo()->meta->title->getTitle() : '';
return my_ogp_clean( '' !== $title ? $title : wp_get_document_title() );
}
// meta description と同じ
function my_ogp_description() {
$desc = function_exists( 'aioseo' ) ? (string) aioseo()->meta->description->getDescription() : '';
if ( '' === $desc ) {
$desc = get_bloginfo( 'description' );
}
return my_ogp_clean( $desc );
}
// canonical と同じ
function my_ogp_url() {
$url = function_exists( 'aioseo' ) ? (string) aioseo()->helpers->canonicalUrl() : '';
if ( '' === $url && is_singular() ) {
$url = (string) wp_get_canonical_url();
}
return $url;
}
// アイキャッチ、なければ共通の画像。array( URL, 幅, 高さ )
function my_ogp_image() {
if ( is_singular() ) {
$thumb_id = get_post_thumbnail_id( get_queried_object_id() );
$image = $thumb_id ? wp_get_attachment_image_src( $thumb_id, 'full' ) : false;
if ( ! empty( $image[0] ) ) {
return array( $image[0], (int) $image[1], (int) $image[2] );
}
}
return array( get_template_directory_uri() . MY_OGP_IMAGE, MY_OGP_IMAGE_W, MY_OGP_IMAGE_H );
}
function my_ogp() {
if ( is_404() || is_search() || is_feed() || my_ogp_theme_outputs() ) {
return;
}
list( $aioseo_og, $aioseo_tw ) = my_ogp_aioseo_social();
if ( ! $aioseo_og ) {
$desc = my_ogp_description();
$url = my_ogp_url();
$image = my_ogp_image();
$type = ( is_singular() && ! is_front_page() ) ? 'article' : 'website';
echo '<meta property="og:type" content="' . esc_attr( $type ) . '">' . "\n";
echo '<meta property="og:site_name" content="' . esc_attr( get_bloginfo( 'name' ) ) . '">' . "\n";
echo '<meta property="og:title" content="' . esc_attr( my_ogp_title() ) . '">' . "\n";
if ( '' !== $desc ) {
echo '<meta property="og:description" content="' . esc_attr( $desc ) . '">' . "\n";
}
if ( '' !== $url ) {
echo '<meta property="og:url" content="' . esc_url( $url ) . '">' . "\n";
}
echo '<meta property="og:image" content="' . esc_url( $image[0] ) . '">' . "\n";
echo '<meta property="og:image:width" content="' . (int) $image[1] . '">' . "\n";
echo '<meta property="og:image:height" content="' . (int) $image[2] . '">' . "\n";
}
if ( ! $aioseo_tw ) {
// タイトル・ディスクリプション・画像は og: の値を使ってもらう
echo '<meta name="twitter:card" content="summary_large_image">' . "\n";
}
}
add_action( 'wp_head', 'my_ogp', 5 );
| 書き方 | 役目 |
|---|---|
add_action( 'wp_head', 'my_ogp', 5 ) |
head の中に出す。優先度を小さくして、head の前のほうに出す |
my_ogp_theme_outputs() |
テーマの OGP の設定が ON なら、何も出さない。テーマの設定の読み方に合わせて書き換える |
my_ogp_aioseo_social() |
SEO のプラグインの Facebook(og:)と X(twitter:)の出力が ON かを見る。ON の分はここでは出さない |
function_exists( 'aioseo' ) |
プラグインがないときや止めたときは、WordPress の関数の値を使う |
try と catch ( \Throwable $e ) |
プラグインの設定の持ち方が変わってエラーになっても、ページを止めない |
getTitle()・getDescription()・canonicalUrl() |
プラグインが <title>・meta description・canonical に出している値を、そのまま使う |
my_ogp_clean() |
タグと文字参照を外し、空白をまとめる。esc_attr() で二重に文字参照にならないようにする |
wp_get_attachment_image_src( …, 'full' ) |
アイキャッチの URL・幅・高さ |
is_404() || is_search() || is_feed() |
検索結果や見つからないページには出さない |
SEO のプラグインの関数は、プラグインの中の作りに頼っているので、プラグインを更新したときは、OGP のタグが今までどおり出ているかを確かめるようにしています。
二重に出さないために
OGP のタグが同じページに 2 組あると、SNS がどちらを読むか分からなくなります。そのため、出す前に、SEO のプラグインのソーシャルの出力と、テーマの OGP の設定を見て、ON になっているほうに任せています。SEO のプラグインは、Facebook 用(og:)と X 用(twitter:)を別々に ON にできるので、この機能も、og: と twitter: を分けて判断しています。
なお、SEO のプラグインやテーマの設定を ON にしたときに、実際にこちらが出なくなるかは、本番の設定を変えないため、今回は試していません。
確かめた結果
本番から複製した作業環境で、記事 3 件とトップのページを HTTP で開き、head の中のタグを取り出して比べました。確かめた記事にはアイキャッチがないため、画像は共通の画像になっています。
| 確かめたこと | 結果 |
|---|---|
| 出た og: のタグ | 4 ページとも、type・site_name・locale・title・description・url・image・image:width・image:height |
og:description と meta description |
4 ページとも同じ |
og:url と canonical |
4 ページとも同じ |
og:title と <title> |
4 ページとも同じ |
og:title・twitter:card の数 |
4 ページとも 1 つずつ(二重になっていない) |
twitter:card |
summary_large_image |
og:image |
共通の画像(1200×630) |
あわせて、この記事の例のコードを検証用スクリプトから読み込み、記事 1 件を開いた状態にして、実際のテーマの関数の出力と比べました。実際のファイルにだけある og:locale の 1 行を除いて、出たタグと値は同じでした。php -l もエラーなしです。
共有したときの見え方の確かめ方
Facebook には、URL を入れると OGP のタグの読み取り結果と、共有したときの見え方を表示する「シェアデバッガー」があります(Meta for Developers のツールで、使うには Facebook へのログインが要ります)。SNS は一度読んだページの情報をしばらく覚えているので、タグを直したあとは、このツールで読み直させてから確かめます。
X については、公式の確かめのツールが今も使えるかを今回確かめられなかったため、ここでは紹介していません。タグそのものは、ページのソースを開いて og: と twitter:card が 1 組ずつあるかを見るのが確実です。
気をつけること
- SEO のプラグインやテーマの OGP の設定をあとで ON にしたら、ページのソースでタグが 1 組だけかを確かめる
- 共通の画像は、テーマのフォルダに置いているので、テーマを更新するときに消さない
- テーマに入れているので、テーマを切り替えると出なくなる
- ページキャッシュを使っているサイトでは、入れたあとにキャッシュを消してから確かめる
まとめ
- SNS でカードが出ないときは、まず head に OGP のタグがあるかを見る
- og:title・og:description・og:url は、SEO のプラグインの title・meta description・canonical と同じ値を使うと、ずれない
- 画像はアイキャッチ、なければ 1200×630 の共通の画像にする
- SEO のプラグインやテーマの OGP の設定が ON のときは出さず、二重にしない
- 見え方は、Facebook のシェアデバッガーやページのソースで確かめる
