Facebook プラグインを使ったときの OGP 画像設定

先日、WordPress 用 Facebook プラグインを使ったときの OGP 画像設定のために、強引に SQL でアイキャッチ画像を設定する方法を書きました。 しかし、わざわざアイキャッチ画像を設定しなくても Facebook プラグインのカスタムフィルタを使用すれば OGP 画像を設定できることに後から気づきました。

方法はプラグインのサポートフォーラムで紹介されていますが、以下のように fb_meta_tags フィルタを使用すればよいのです。

function my_ogp_filter( $meta_tags ) {
  $meta_tags['http://ogp.me/ns#image'][] = array(
    'url' => 'http://example.com/wp-content/uploads/2012/12/logo200x200.png',
    'type' => 'image/png',
    'width' => 200,
    'height' => 200
  );
  return $meta_tags;
}

add_filter( 'fb_meta_tags', 'my_ogp_filter' );

ただし、フォーラムで「add a fallback image」と書かれていますが、単純に画像もう 1枚分の Meta タグを加えているだけなので、既にアイキャッチ画像が設定されているポストでは OGP 画像設定用タグ (og:image 関連) が 2回含まれることになります。 それでも Facebook 開発者ページを見ると「You may include multiple og:image tags to associate multiple images with your page.」と書かれているので問題ないようです。

Facebook for WordPress と Social Interaction Analytics

今回は Facebook と Google の Social Interaction Analytics の話です。 Facebook 関連シリーズ (1回目2回目) も今回で一区切りです。

初期化コードとイベントリスナー

詳細は Social Interaction Analytics のページに書いてあるので簡単にすませますが、Facebook の「いいね!」ボタンが押されたのをトラックするには以下のようなコードでイベントリスナーを登録します。

FB.Event.subscribe('edge.create', function(targetUrl) {
  _gaq.push(['_trackSocial', 'facebook', 'like', targetUrl]);
});

先の記事に書いた通り、fb_xd_fragment の件もあって WordPress で「いいね!」ボタン等 Facebook の機能を使うのであれば、Facebook for WordPress プラグインがお勧めです。 しかし、ここでの問題は上のコードをどこに置いたらよいかということです。 Facebook for WordPress を使用すると以下のようなコードがページに埋め込まれます。

<script type='text/javascript'>
/* <![CDATA[ */
window.fbAsyncInit=function(){FB.init({"channelUrl":"https:\/\/hetarena.com\/wp-content\/plugins\/facebook\/channel.php","status":true,"cookie":true,"xfbml":true,"appId":"my_app_id"});}
/* ]]> */
</script>
<div id="fb-root"></div><script type="text/javascript">(function(d){var js,id="facebook-jssdk",ref=d.getElementsByTagName("script")[0];if(d.getElementById(id)){return;}js=d.createElement("script");js.id=id;js.async=true;js.src="http:\/\/connect.facebook.net\/ja_JP\/all.js";ref.parentNode.insertBefore(js,ref);}(document));</script>

これは非同期のスクリプトファイル読み込み処理と初期化コードです。 非同期のため、何も考えずに先のイベントリスナー登録コードを書いてしまうと FB という変数が未定義でエラーとなってしまいます。 プラグインの出力する window.fbAsyncInit の関数の FB.init の後に先のイベントリスナー登録コードを埋め込むことができれば良いのですが、プラグインに手を加えたくないですね。 どうすれば良いのでしょう?

facebook_jssdk_init_extras フィルター

実はちゃんと ‘facebook_jssdk_init_extras’ という名前でそれ用のフィルターが用意されています。 ここにコールバックを登録しておけば目的の位置にコードを出力することができます。 プラグインの readme.txt の中で以下のように説明されています。

* `facebook_jssdk_init_extras` – add extra JavaScript to the `fbAsyncInit` JavaScript function called after the Facebook JavaScript SDK is loaded

というわけで以下の様なコードを function.php に書いておけばオッケーです。

add_filter('facebook_jssdk_init_extras', 'my_facebook_init');

function my_facebook_init() {
  return
"
  FB.Event.subscribe('edge.create', function(targetUrl) {
    _gaq.push(['_trackSocial', 'facebook', 'like', targetUrl]);
  });
";

}

readme.txt やソースを読むといいことがあるよということで。

フィルタじゃNG! fb_xd_fragment の問題への正しい対処の仕方

「fb_xd_fragment が Google Analytics のログに残るのは Facebook の「いいね!」ボタンのバグなので、Analytics 側でフィルタの設定を行いましょう」という記事が世の中に溢れています。 ちょっと気になったので調べてみたところ、根本的な対処が必要であることがわかったのでメモ書きしておきます。

どうすればよいのか

先の現象のことは実は Facebook JavaScript SDK のドキュメントできちんと説明されています。 詳細はそちらを読んでいただくとして結論だけ言うと、対策は channelUrl というパラメータを設定して対応するページを用意することです。 channelUrl を設定するとパフォーマンスが向上し、逆に設定しないと以下のような問題が発生するので、設定することが強く推奨されています。 Facebook からするとこれらの問題はバグというよりも仕様なのでしょう。

  1. フレームを使うと Social Plugins が表示されないことがあります。
  2. 自動再生ビデオやオーディオを埋め込むと 2つのストリームを再生してしまいます。
  3. channelUrl パラメータを設定しないと fb_xd_bust や fb_xd_fragment といったパラメータつきのログが残ります。

というわけで fb_xd_fragment がログに出ているときの正しい対処法は channelUrl を設定することです。 ログのフィルタはそれができない場合の次善策ではありますが、1 や 2 の現象に関しては全く効果がありません。

具体的な対処方法は

JavaScript SDK ドキュメント からの抜粋ですが、以下のようなページを用意します。 PHP での例です。

 <?php
 $cache_expire = 60*60*24*365;
 header("Pragma: public");
 header("Cache-Control: max-age=".$cache_expire);
 header('Expires: ' . gmdate('D, d M Y H:i:s', time()+$cache_expire) . ' GMT');
 ?>
 <script src="//connect.facebook.net/en_US/all.js"></script>

そして「いいね!」ボタン等を設置するページに以下の JavaScript を埋め込み、非同期 js ファイルロードのコードと組み合わせて使います。 channelUrl のところに作成したページの URL を指定します。

<script>
  window.fbAsyncInit = function() {
    // init the FB JS SDK
    FB.init({
      appId      : 'YOUR_APP_ID', // App ID from the App Dashboard
      channelUrl : '//WWW.YOUR_DOMAIN.COM/channel.html', // Channel File for x-domain communication
      status     : true, // check the login status upon init?
      cookie     : true, // set sessions cookies to allow your server to access the session?
      xfbml      : true  // parse XFBML tags on this page?
    });

    // Additional initialization code such as adding Event Listeners goes here

  };
</script>

JavaScript の書かれたページと channelUrl のページとで document.domain およびプロトコルを合わせておかなければならないとのことなので、環境によってはサーバーサイドで処理が必要かも知れません。

WordPress を使用しているのであればずっと簡単に解決する方法があります。 Facebook for WordPress プラグインを使うのです。 これをインストールするだけで先の 2つの処理を加えてくれます。

余計なひとこと

今回、ちょっとがっかりなのは fb_xd_fragment について書いた記事は多いものの、channelUrl の対策をきちんと説明した記事は見つからなかったことです。 だからこそこうして記事にしているというのはありますが、残念です。

WordPress で簡単に OGP の設定を行う方法

Open Graph Protocol (OGP) についての記事は小難しいものが多いように見えたので触らないでおいたのですが、とりあえず対応するにはセマンティックな meta タグを埋め込むぐらいの話のようなので、これは対応せねばと思いました。 今回は WordPress を OGP に対応させるためにしたことをまとめます。

Facebook for WordPress プラグインを使うのがお手軽

OGP 対応で一番簡単なのは公式プラグインである Fackbook for WordPress をインストールすることです。 インストールしただけで特に設定をしなくても OGP 対応タグを記事中に埋め込むようになります。 「いいね」ボタン等の機能は無効にしておくことができ、埋め込む App ID の指定もできます。 公式プラグインという安心感があるので OGP 対応が目的の場合も Facebook for WordPress を選択するのが、良いように思います。

私の場合、App ID は今回初めて取得しました。 まだ、十分に調べることが出来ていませんが、App ID を記事に埋め込むことで様々な機能が有効になるので、きちんと設定しておくべきです。

以下 Facebook のサイト上で行うアプリ設定についての話です。 記事に埋め込んで機能させるためには、その記事を公開するサイトのドメイン (ここなら hetarena.com) を App Domains として設定しておかねばなりません。 また、App Domains に設定するためには、そのアプリと Facebook 統合方法でその URL が使われていなければなりません。 何にも設定しないと App Domains 登録でエラーになるので、例えば「Website with Facebook Login」のサイト URL として https://hetarena.com/ を設定しておきます。 こうすることで App Domains にも hetarena.com を設定できるようになります。

できるだけシェイプアップしたい

本当に簡単に済ませるのであればここまでで、ここから先はこだわりの話です。 OGP 対応のみが目的のとき、Facebook for WordPress の出力する余分な JavaScript が記事に埋め込まれるのが気になります。 そこで、Facebook for WordPress のソースを見てみると、OGP 対応は open-graph-protocol.php というファイルの Facebook_Open_Graph_Protocol というクラスだけを使えば済むことに気が付きました。 app_id と locale は呼び出し元クラスの情報を使っているのですが、以下のように強引に書き換えてしまいます。 my app id は自分 App ID です。 locale については特にデバッガーもエラーを吐かないので、省略しました。

--- a/includes/open-graph-protocol.php
+++ b/includes/open-graph-protocol.php
@@ -121,12 +121,7 @@ class Facebook_Open_Graph_Protocol {
                        self::OGP_NS . 'type' => 'website'
                );

-               if ( isset( $facebook_loader ) ) {
-                       if ( isset( $facebook_loader->locale ) )
-                               $meta_tags[ self::OGP_NS . 'locale' ] = $facebook_loader->locale;
-                       if ( isset( $facebook_loader->credentials ) && isset( $facebook_loader->credentials['app_id'] ) && $facebook_loader->credentials['app_id'] )
-                               $meta_tags[ self::FB_NS . 'app_id' ] = $facebook_loader->credentials['app_id'];
-               }
+               $meta_tags[ self::FB_NS . 'app_id' ]  = 'my app id';

                if ( is_home() || is_front_page() ) {
                        $meta_tags[ self::OGP_NS . 'title' ] = get_bloginfo( 'name' );

あとは functions.php に以下を入れます。 open-graph-protocol.php へのパスは適切に書きましょう。

require_once( '/path_to_ogp/open-graph-protocol.php' );
add_action( 'wp_head', array( 'Facebook_Open_Graph_Protocol', 'add_og_protocol' ) );

これで余分な出力はなくなり、OGP の meta タグのみ出力されるようになりました。

…とここまで書いてアレなのですが、埋め込まれている JavaScript に重要な働きがあることがわかりました。 fb_xd_fragment がログに残る件がらみなのですが、詳細は別記事でご確認ください。 そういうわけでこのようにクラスを切り出して使うのはお勧めしません。 Facebook for WordPress をそのまま使いましょう。 (この段落は 2012/12/4 追記)

アイキャッチイメージを記事に設定する

Facebook for WordPress (Facebook_Open_Graph_Protocol クラス) の動作では、記事に設定された「アイキャッチ画像」の情報を image プロパティとして埋め込みます。 Facebook のデバッガーによれば縦横 200px 以上のイメージをきちんと設定しておくことが推奨とのことです。 これまでアイキャッチ画像は使っていなかったので、新たに 200px 四方のロゴをアップロードして全ての記事のアイキャッチ画像として設定することにします。

(2013/1/20 追記: もっと手軽な方法がありました。)

まず、記事に見える形で表示したくないので、テーマファイルから以下の行を削除しました。

<?php the_post_thumbnail(); ?>

続いて記事へのアイキャッチ画像の設定ですが、面倒なので SQL で実行することにしました。 以下の SQL 文はアイキャッチ画像が設定されていない post/page に対して ID 654 の画像をアイキャッチ画像として設定するためのものです。

START TRANSACTION;

INSERT INTO wp_postmeta (post_id, meta_key, meta_value)
SELECT id, '_thumbnail_id', 654
FROM wp_posts
WHERE post_type IN ('page', 'post')
AND NOT EXISTS
(SELECT * FROM wp_postmeta
 WHERE meta_key = '_thumbnail_id'
 AND wp_postmeta.post_id = wp_posts.id);

COMMIT;

何か失敗したときに Rollback ができるようにトランザクションを有効にして実行しています。 これで image プロパティも meta タグとして埋め込まれるようになりました。 これらを実行する時は、画像 ID だけでなくテーブル名も自分の環境に合わせてください。 マルチサイト環境ならば wp_2_postmeta、wp_3_postmeta、… となりますね。

これで「簡単な」なのかという声が聞こえそうですが、やっている内容に比べたら簡単にやっているのではないでしょうか…。(苦しい)