SNSでリッチ表示してくれるOGPをWordPressに、プラグインを使わず設定する
photo credit: mkhmarketing via photopin cc

SNSでリッチ表示してくれるOGPをWordPressに、プラグインを使わず設定する

FacebookやTwitterなどのSNSで記事がシェアされた時、リッチに表示されるOGPの設定をプラグインを使わず実装します。OGPについてよくわからない方は、予備知識として、こちらの記事に目を通してください。

また、プログラミング言語のphpの知識も必要になります。ドットインストールなどのプログラミング学習サイトで基礎知識をつけておきましょう。

OGPの設定手順

OGPの設定で必要となるコードやタグを、大きく2つに分けてみました。

  1. prefix属性の記述
  2. <meta>要素の記述
<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# website: http://ogp.me/ns/website#">

<meta property="fb:app_id" content="000000000000000" />
<meta property="og:type"   content="article" />
<meta property="og:url"    content="https://millkeyweb.com/" />
<meta property="og:title"  content="Sample" />
<meta property="og:image"  content="https://millkeyweb.com/xxx.png" />
<meta property="og:description"  content="Sample Description" />
<meta property="og:site_name"  content="MILL KEY WEB" />
...
</head>

1 は、<meta>要素のproperty属性に「og:」「fb:」などの記述を使えるようにする指定です。

2 は、FacebookなどのSNSにページの内容を伝えるためのタグです。この値によってシェアされた時のタイトルやURL、アイキャッチなどが変わります。

静的ページなら、このサンプルコードを運営しているサイトの内容に合わせて書き換えて、記入すればOGPの設定は完了です。今回は動的サイトのWordPressに設定するので、前回の記事で書いたWork Sessionsの内容を踏まえて、ページによって表示を変えてみます。

実装手順

  1. <head>タグ内にprefixを書く
  2. 関数にする
  3. <meta>タグを書く
  4. 関数にする
  5. 確認する

<head>タグ内にprefixを書く

まずOGPの<meta>要素のproperty属性に「og:」「fb:」などの記述が使えるように、<head>内にprefixを指定します。

WordPressでは、記事ページとそれ以外のページがあるので、記事ページには、オブジェクトタイプのarticleを指定して、「article:」も使えるようにしたいと思います。

  1. 記事ページ:
    主にsingle.php, page.phpで出力されるページ
  2. それ以外のページ:
    home.php, archive.phpなどで出力されるブログ記事の一覧ページなど

記事ページ

<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# article: http://ogp.me/ns/article#">

それ以外のページ

<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# website: http://ogp.me/ns/website#">

上記のコードを条件分岐して、表示すれば手っ取り早く実現できます。 WordPressの場合、header.php内に<head>...</head>タグがあると思います。そこに書いてみましょう。条件分岐には、個別の記事を表示しているかどうかチェックするするis_singularが使えます。

<?php if (is_singular()) { ?>
  <head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# article: http://ogp.me/ns/article#">
<?php } else { ?>
  <head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# website: http://ogp.me/ns/website#">
<?php } ?>

これで表示の切り替えができました。実際にページを開いて確認して見てください。

ですが、これではheader.php内に同じようなコードが増えて見通しが悪いと思いませんか?あとで編集するにも邪魔になりそうです。

prefixを関数にする

WordPressのfunctions.phpにまとめて関数にしてしまった方が良さそうです。header.phpではその関数を使って表示するようにしてみましょう。

functions.phpogp_prefixという名前で関数を作ってみます。関数の行う処理は、とりあえず先ほどと同じような処理にしておきます。

function ogp_prefix() {
  if (!is_admin()) {
    if (is_singular()) {
      echo '<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# article: http://ogp.me/ns/article#">';
    } else {
      echo '<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# website: http://ogp.me/ns/website#">';
    }
  }
}

これで<head>タグを表示する関数ができたので、header.phpも関数を使って表示するように変更しましょう。

<?php ogp_prefix(); ?>
...
</head>

変更したら表示が正しいか確認して見てください。header.phpもスッキリしましたね。

prefix関数の最適化

しかし、また問題が発生してしまいました。header.phpをみた時</head>の閉じタグはあるのにどこから始まっているかわかりません。あとで編集するとき困りそうです。もう少し改良を加えてみましょう。

まず、<head>タグはheader.phpに残します。条件分岐しているタグも同じような部分があるので、まとめて、異なる部分だけ条件分岐するようにしてみます。

function ogp_prefix() {
  if (!is_admin()) {
    $ogp_ns = 'og: http://ogp.me/ns#';
    $fb_ns  = 'fb: http://ogp.me/ns/fb#';

    if (!is_singular()) {
      $type_ns = 'website: http://ogp.me/ns/website#';
    } else {
      $type_ns = 'article: http://ogp.me/ns/article#';
    }
    printf('prefix="%1$s %2$s %3$s"', $ogp_ns, $fb_ns, $type_ns);
  }
}
<head <?php ogp_prefix(); ?>>
...
</head>

これでheader.php<head>タグが分かるようになり、関数も追加や編集が効きそうになりました。prefix部分は、これで完成にしておきます。

<meta>タグを書く

まずは、prefixを書いた時のように表示したいコードを書きます。今回8つのpropertyを取り扱います。それぞれについてどのように値を入れるか説明していきます。

記事ページ

<meta property="og:type" content="article">
<meta property="og:url" content="記事ページのURL">
<meta property="og:title" content="記事タイトル">
<meta property="og:image" content="アイキャッチ画像">
<meta property="og:site_name" content="サイト名">
<meta property="og:description" content="記事の抜粋だいたい80~90文字がオススメ">
<meta property="fb:app_id" content="FacebookアプリのID">
<meta property="article:publisher" content="FacebookページのURL">

それ以外のページ

<meta property="og:type" content="website">
<meta property="og:url" content="サイトURL">
<meta property="og:title" content="サイト名">
<meta property="og:image" content="画像URL">
<meta property="og:site_name" content="サイト名">
<meta property="og:description" content="サイトの説明">
<meta property="fb:app_id" content="FacebookアプリのID">

prefixの時の記述を踏まえて、先に関数にしてしまいましょう。下記コードはcontentの値は変数にして表示するようにしてみました。記事の情報を取得したいので、global $post;で関数内から変数$postを扱えるようにしています。

function ogp_meta() {
  if (!is_admin()) {

    global $post;
    $type = '';
    $url  = '';
    $site_name = '';
    $title = '';
    $image = '';
    $description = '';
    $fb_app_id = '';
    $publisher = '';

    echo '<meta property="og:type" content="' . $type . '">';
    echo '<meta property="og:url" content="' . $url . '">';
    echo '<meta property="og:title" content="' . $title . '">';
    echo '<meta property="og:image" content="' . $image . '">';
    echo '<meta property="og:site_name" content="' . $site_name . '">';
    echo '<meta property="og:description" content="' . $description . '">';
    echo '<meta property="fb:app_id" content="' . $fb_app_id . '">';

    if (is_singular()) {
      echo '<meta property="article:publisher" content="' . $publisher . '">';
    }
  }
}
<head <?php ogp_prefix(); ?>>
  <?php ogp_meta(); ?>
  ...
</head>

この<meta>タグを土台にして、contentの内容を入れていきます。

contentに値を入れる

contentに値をog:typeから順に入れていきます。Work Sessionsで実現したいことも含めてコードを書いていきます。

og:type

og:typeには、記事ページにはarticleそれ以外をwebsiteを指定したいと思います。

$type = (is_singular()) ? 'article' : 'website';

og:url

URLは、記事ページはそのページのURLを指定して、それ以外のページ、例えばカテゴリーページ、タグページなどはHOME URLを指定してみます。

$url = (is_singular()) ? esc_url(get_permalink($post->ID)) : esc_url(home_url('/'));

og:title

タイトルは記事ページは記事タイトル、それ以外はサイト名を指定してみます。サイト名は後述する$site_name変数を先に書いておいてそれを使用します。

$title = (is_singular()) ? esc_attr($post->post_title) : $site_name;

og:image

シェアされた時のアイキャッチとなる画像は、まずデフォルトの画像を用意して、記事ページでは、サムネイルがある時はサムネイルを設定して、ない場合はコンテンツの中の最初の画像を設定されるようにします。

サムネイルもコンテンツ内にも画像がない場合は、デフォルトの画像を設定させます。

$image = 'http://example.com/xxx.png';
if (is_singular()) {
  if (function_exists('has_post_thumbnail') AND has_post_thumbnail($post->ID)) {
    $attachment = wp_get_attachment_image_src(get_post_thumbnail_id($post->ID), 'full');
    $image = esc_url($attachment[0]);
  } elseif (preg_match('/<imgs[^>]*src=["']?([^>"']+)/i', $post->post_content, $match)) {
    $image = esc_url($match[1]);
  }
}

サムネイル画像を取得するとき、引数にfullを入れているのは、デフォルトだと150×150pxを取得するからです。これでは、Facebookの最低ラインの200×200pxより小さいくなってしまいます。

fullにしておけばFacebookの推奨する1200×630pxのサイズに近づけるでしょう。

og:site_name

サイト名を指定します。

$site_name = esc_attr(get_option('blogname'));

サイト名を変更することがなければ直接書いてもいいと思います。

og:description

記事ページでは、コンテンツの抜粋をここでは90文字で指定します。それ以外では、サイトの説明文を指定します。

if (is_singular()) {
  $description  = strip_tags($post->post_excerpt ? $post->post_excerpt : $post->post_content);
  $description  = mb_substr($description, 0, 90) . '...';
} else {
  $description = esc_attr(get_option('blogdescription'));
}

fb:app_id

Facebookアプリを先に作っておいてください。作成したらapp_idを指定します。

$fb_app_id = '000000000000000';

article:publisher

FacebookページをもっていたらFacebookページのURLをしていします。指定するとFacebookでシェアされた時Followボタンが表示されます。

$publisher = 'https://www.facebook.com/example';

<meta>タグのコードまとめ

function ogp_meta() {
  if (!is_admin()) {

    global $post;
    $type = (is_singular()) ? 'article' : 'website';
    $url = (is_singular()) ? esc_url(get_permalink($post->ID)) : esc_url(home_url('/'));
    $site_name = esc_attr(get_option('blogname'));
    $title = (is_singular()) ? esc_attr($post->post_title) : $site_name;
    $image = 'http://example.com/xxx.png';
    if (is_singular()) {
      if (function_exists('has_post_thumbnail') AND has_post_thumbnail($post->ID)) {
        $attachment = wp_get_attachment_image_src(get_post_thumbnail_id($post->ID), 'full');
        $image = esc_url($attachment[0]);
      } elseif (preg_match('/<imgs[^>]*src=["']?([^>"']+)/i', $post->post_content, $match)) {
        $image = esc_url($match[1]);
      }
    }
    if (is_singular()) {
      $description  = strip_tags($post->post_excerpt ? $post->post_excerpt : $post->post_content);
      $description  = mb_substr($description, 0, 90) . '...';
    } else {
      $description = esc_attr(get_option('blogdescription'));
    }
    $fb_app_id = '000000000000000';
    $publisher = 'https://www.facebook.com/example';

    echo '<meta property="og:type" content="' . $type . '">';
    echo '<meta property="og:url" content="' . $url . '">';
    echo '<meta property="og:title" content="' . $title . '">';
    echo '<meta property="og:image" content="' . $image . '">';
    echo '<meta property="og:site_name" content="' . $site_name . '">';
    echo '<meta property="og:description" content="' . $description . '">';
    echo '<meta property="fb:app_id" content="' . $fb_app_id . '">';

    if (is_singular()) {
      echo '<meta property="article:publisher" content="' . $publisher . '">';
    }
  }
}

これでOGPの設定ができました。しかし、見て分かるようにかなり無駄が多いです。とりあえず現段階で表示は正しくされるか確認してみましょう。

<meta>タグのコードを最適化

OGPの設定はできましたが、<meta>タグの共通する部分があるのでもっとコンパクトにまとめれそうです。是非考えてみてください。

私は、以下のようにまとめてみました。そして、header.phpに関数を書いて表示していたのから関数を取り除いて、wp_headのアクションに追加して表示されるようにしています。

function ogp_meta() {
  if (!is_admin()) {

    global $post;
    $format = '<meta property="%1$s" content="%2$s">';
    $type = 'website';
    $url = esc_url(home_url('/'));
    $site_name = esc_attr(get_option('blogname'));
    $title = $site_name;
    $image = 'http://example.com/xxx.png';
    $description = esc_attr(get_option('blogdescription'));
    $fb_app_id = '000000000000000';

    if (is_singular()) {
      $type = 'article';
      $url = esc_url(get_permalink($post->ID));
      $title = esc_attr($post->post_title);
      $description  = strip_tags($post->post_excerpt ? $post->post_excerpt : $post->post_content);
      $description  = mb_substr($description, 0, 90) . '...';
      if (function_exists('has_post_thumbnail') AND has_post_thumbnail($post->ID)) {
        $attachment = wp_get_attachment_image_src(get_post_thumbnail_id($post->ID), 'full');
        $image = esc_url($attachment[0]);
      } elseif (preg_match('/<imgs[^>]*src=["']?([^>"']+)/i', $post->post_content, $match)) {
        $image = esc_url($match[1]);
      }
      $publisher = 'https://www.facebook.com/example';
      printf($format, 'article:publisher', $publisher);
    }

    $args = array(
      'og:type'  => $type,
      'og:url'   => $url,
      'og:title' => $title,
      'og:image' => $image,
      'og:site_name' => $site_name,
      'og:description' => $description,
      'fb:app_id'      => $fb_app_id
    );
    foreach ($args as $key => $value) {
      printf($format, $key, $value);
    }
  }
}
add_action('wp_head', 'ogp_meta');

もっといい方法があれば教えて下さい、お願いします。

OGPコードのまとめ、最終確認

ここまでのコードを全てまとめると以下のようになっています。

functions.php

function ogp_prefix() {
  if (!is_admin()) {
    $ogp_ns = 'og: http://ogp.me/ns#';
    $fb_ns  = 'fb: http://ogp.me/ns/fb#';

    if (!is_singular()) {
      $type_ns = 'website: http://ogp.me/ns/website#';
    } else {
      $type_ns = 'article: http://ogp.me/ns/article#';
    }
    printf('prefix="%1$s %2$s %3$s"', $ogp_ns, $fb_ns, $type_ns);
  }
}

function ogp_meta() {
  if (!is_admin()) {

    global $post;
    $format = '<meta property="%1$s" content="%2$s">';
    $type = 'website';
    $url = esc_url(home_url('/'));
    $site_name = esc_attr(get_option('blogname'));
    $title = $site_name;
    $image = 'http://example.com/xxx.png';
    $description = esc_attr(get_option('blogdescription'));
    $fb_app_id = '000000000000000';

    if (is_singular()) {
      $type = 'article';
      $url = esc_url(get_permalink($post->ID));
      $title = esc_attr($post->post_title);
      $description  = strip_tags($post->post_excerpt ? $post->post_excerpt : $post->post_content);
      $description  = mb_substr($description, 0, 90) . '...';
      if (function_exists('has_post_thumbnail') AND has_post_thumbnail($post->ID)) {
        $attachment = wp_get_attachment_image_src(get_post_thumbnail_id($post->ID), 'full');
        $image = esc_url($attachment[0]);
      } elseif (preg_match('/<imgs[^>]*src=["']?([^>"']+)/i', $post->post_content, $match)) {
        $image = esc_url($match[1]);
      }
      $publisher = 'https://www.facebook.com/example';
      printf($format, 'article:publisher', $publisher);
    }

    $args = array(
      'og:type'  => $type,
      'og:url'   => $url,
      'og:title' => $title,
      'og:image' => $image,
      'og:site_name' => $site_name,
      'og:description' => $description,
      'fb:app_id'      => $fb_app_id
    );
    foreach ($args as $key => $value) {
      printf($format, $key, $value);
    }
  }
}
add_action('wp_head', 'ogp_meta');

header.php

<head <?php ogp_prefix(); ?>>
...
<?php wp_head(); ?>
...
</head>

Open Graph Debugger で確認

最後にOGPが適切に表示されているか、FacebookのOpen Graph Debuggerで確認してみましょう。下記サイトで、サイトURLを入力すると調べる事ができます。

エラーがなければ問題ありません。
OGPについて詳しい説明はしませんでした。こちらの記事ではもう少し詳しく書きましたので合わせてお読みいただくと理解が深まるかもしれません。

あとがき

誰か一人でも参考になる人がいてくれれば幸いです。

ブログを書く時、偉そうに説明なんか書いていいものか悩むのですが、どこかのブログ論では曖昧な言い方より、見えを張って書くべきだとのことですので、もっと自信をもって頑張ります。