5分でわかる Blog を Facebook インスタント記事 (Instant Articles) に対応させる方法

運営中の Blog などから Facebook インスタント記事 (Instant Articles) 向けの RSS フィードを配信してインスタント記事に対応させる手順を解説しています。

Facebook インスタント記事 (Instant Articles) は、インターネットメディアなどが、Facebook 内で自分たちの記事を配信することができる仕組み。ユーザーは Facebook アプリ内で記事を受け取り、閲覧してそれをシェアしたりすることができます。

簡単に言ってしまえば、Facebook アプリ自体がニュースリーダーになるような感覚で、ユーザーは Facebook の外に出ることなく、記事を読むことができるのと、記事自体も専用フォーマットによって読み込み速度が速く、快適な閲覧ができるというのが売りになっています。

Facebook インスタント記事

元々は一部の限られた大手メディア (例として The New York Times、National Geographic、BuzzFeed など) のみに提供されていた機能ですが、先週 (2016年 4月 12日 / 13日 米国時間) 行われた Facebook の開発者向けカンファレンス 「F8 - Facebook Developer Conference」(毎年 4月に開催) で、すべてのメディア向けにこの機能が解放されました。

早速、開発者向けのドキュメントも提供され (一部は日本語翻訳あり)、大手メディアサイトだけでなく、Blog などを運営している人なら個人でもこのインスタント記事を使って記事を配信することが可能になっています。

そこでこの Blog でも試しにインスタント記事に対応させてみました。いくつか面倒な点もあったのですが、そこで得た知識を恒例の 5分でわかるシリーズとして下記にまとめます。

ちなみにインスタント記事の配信方法は 「インスタント記事 API」 を使用する方法と 「RSS フィード」 によるものと 2種類から選択できますが、今回は Blog などで対応しやすい RSS フィードによる配信方法を前提に解説しています。これからインスタント記事の配信をお考えの方がいれば参考にしてみてください。

なお、インスタント記事の開発者向けドキュメントのうち、この記事執筆時点でまだ日本語訳がなかった 「Instant Articles Format Reference (インスタント記事で使用する HTML のリファレンス)」 についても重要と思われる部分を日本語で解説しています。

前提条件

まず解説を始める前に、インスタント記事に対応させる場合に、対象となるメディアサイトや Blog が最低限下記の 2点を満たしている必要があります。満たしていない場合は必要な条件を事前にそろえておいてください。

  1. 対応させるメディアや Blog などで Facebook ページを開設済みであること (開設していない場合は事前に作成
  2. 公開済みの記事が最低 10件以上 ※ あること (フォーマットレビューで再審査を食らった時にはさらに 10件必要になるので、余裕を持って 30~40件くらいはあった方がよい)

※ 私が最初に作業を始めた時はレビューのために 「最低 50件」 記事を用意しろと書かれていたのですが、途中でシレっと 10件になっていました。ドキュメント上はまだ 50件の表記が残っているみたいですが、50件記事がない RSS フィードでもレビュー申請が出せたので。とりあえずハードルが少し下がった。

条件がそろっている場合は次のセクションから順を追ってインスタント記事に対応させる方法を解説していきます。

インスタント記事を有効に

まずは Facebook ページでインスタント記事を有効にします。Facebook にログインした状態で下記のページから 「Sign up」 ボタンを押します。

次のページで下記のように管理している Facebook ページの一覧が表示されると思いますので、インスタント記事に対応させたいページのラジオボタンにチェックを入れて、「Enable Instant Articles」 ボタンを押します。上の利用規約へのチェックをしないと押せませんので、事前に確認の上、チェックを入れてください。

Facebook インスタント記事

すると、該当するページの管理画面に移動しますが、下記のように設定画面のサイドメニューに 「インスタント記事」 の項目が追加されるのがわかると思います。これでインスタント記事が有効になりました。

Facebook ページの管理画面に 「インスタント記事」 が追加された状態

インスタント記事の設定 (前半)

前の手順で開いた 「インスタント記事」 の設定画面を開いてください。「Initial Setup」 の項目に説明が書かれていますので、その通りに進めていきますが、まずはインスタント記事配信元の URL 登録を行います。

「Tools」 というエリアに 「Claim Your URL」 という項目がありますので、そこを開くと、下記のような感じでそのページ専用の <meta> タグが表示されると思います。

これをコピーして、インスタント記事に対応させる Web サイト、トップページの head 要素内に貼り付けましょう。要するに Web サイト所有者の確認用です。

インスタント記事

<meta> タグを間違いなく設置し終わったら管理画面に戻り、「URL」 の項目に Web サイトの URL を貼り付けます。「example.com」 のように入力すれば大丈夫。

もしドメイン内の特定のディレクトリがトップページになる場合は、例えば 「example.com/blog」 のように入力します。詳しい URL の入力方法は下記にドキュメントがありますので確認してください。

URL を入力したら、その下にある 「Claim URL」 ボタンを押します。すると URL が登録されると思います。

Facebook 上での設定は一旦ここまで。次に RSS フィードの作成を進めます。

インスタント記事用 RSS フィードのフォーマット

ここからはインスタント記事を配信するための RSS フィードを作っていきます。Web サイトに CMS が導入されている場合、新しいテンプレートを設定して任意の場所に専用 RSS フィードが出力されるようにしてください。

インスタント記事用 RSS フィードの基本フォーマットは下記のようになります。

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Web サイトのタイトル</title>
    <link>https://example.com/</link> <!--Web サイト URL-->
    <description>Web サイトの説明文</description>
    <language>ja-jp</language>
    <lastBuildDate>2016-04-17T11:51:01Z</lastBuildDate> <!--RSS フィードの最終更新日時-->

    <!--item 要素 1つが 1記事-->
    <item>
      <title>記事のタイトル</title>
      <link>https://example.com/article/article-01.html</link> <!--元記事の URL-->
      <guid>2fd4e1c67a2d28fced849ee1bb76e7391b93eb12</guid> <!--各記事ごとに重複しない一意の ID-->
      <pubDate>2016-04-17T11:51:01Z</pubDate> <!--記事の公開日時-->
      <author>Yoshiki Kato</author> <!--運営者の名前-->
      <description>記事のサマリー</description>
      <content:encoded>
        <!--ここから記事の内容 / 必ず <![CDATA[ ]]> 内に HTML を記述すること-->
        <![CDATA[
        <!DOCTYPE html>
        <html lang="ja" prefix="op: http://media.facebook.com/op#">
          <head>
            <meta charset="utf-8">
            <meta property="op:markup_version" content="v1.0">
            <meta property="fb:article_style" content="default"> <!--スタイルの設定(後述)-->
            <meta property="fb:use_automatic_ad_placement" content="true"> <!--広告自動配置のためのタグ(後述)-->
            <link rel="canonical" href="https://example.com/article/article-01.html"> <!--元記事の URL-->
          </head>
          <body>
            <article>
              <header>
                <figure>
                  <img src="https://example.com/article/article-01.jpg">
                  <figcaption>記事のタイトル</figcaption>
                </figure>
                <h1>記事のタイトル</h1>
                <h2>記事のリード文(記事のサマリー)</h2>
                <h3 class="op-kicker">キッカー(単文のキャッチ)</h3>
                 <address> <!--執筆者のクレジット(複数いる場合は address 要素を複数記述)-->
                   <a rel="facebook" href="https://www.facebook.com/burnworks">Yoshiki Kato</a>
                 </address>
                <time class="op-published" dateTime="2016-04-17T11:35:44+09:00">April 17, 2016 11:35 AM</time> <!--記事の公開日時-->
                <time class="op-modified" dateTime="2016-04-17T20:51:01+09:00">April 17, 2016  8:51 PM</time> <!--記事の更新日時-->
                <figure class="op-ad"> <!--広告タグ(後述)-->
                  <iframe width="320" height="50" style="border:0;margin:0;" src="https://www.facebook.com/adnw_request?"></iframe>
                </figure>
              </header>

              <p>ここに記事の本文</p>

              <ul>
                <li>リストなども入れ子にしなければ普通に使えます</li>
              </ul>

              <figure><img alt="写真:写真の説明" src="https://example.com/article/01.jpg" width="1600" height="1200" /></figure>

              <figure>
                <img src="https://example.com/article/01.jpg" width="1600" height="1200" />
                <figcaption>写真:写真の説明</figcaption>
              </figure>

              <figure class="op-social"><iframe width="1280" height="720" src="https://www.youtube.com/embed/****" frameborder="0" allowfullscreen></iframe></figure>

              <footer>
                <ul class="op-related-articles"> <!--関連記事(後述)-->
                  <li><a href="https://example.com/article/article-02.html"></a></li>
                  <li><a href="https://example.com/article/article-03.html"></a></li>
                  <li><a href="https://example.com/article/article-04.html"></a></li>
                </ul>
                <aside>
                  <p>フッタに注釈など入れたい場合は aside 要素で。<a href="...">リンクも化</a>。</p>
                </aside>
                <small>Yoshiki Kato @burnworks</small> <!--署名-->
              </footer>
            </article>
          </body>
        </html>
        ]]>
      </content:encoded>
    </item>
    <!--item 要素ここまで-->

  </channel>
</rss>

すべてが必須要素ではないのと、他にも使える要素がありますので、その辺はあとでまとめて解説しますが、上記のサンプルソースが、多くの Web サイトで使用するオーソドックスな内容になると思われます。

フォーマット上の注意事項

インスタント記事用 RSS フィード内で記述する HTML で注意すべき点がいくつかあります。

今回は元々 Blog で書いた記事をそのまま流用してインスタント記事用 RSS フィードに書き出すという前提で解説していますので、元記事の HTML によっては RSS フィードとして出力する際、HTML を大きく変換しないといけない場合もあると思います。インスタント記事用にゼロから専用記事を書きます、あるいは書き直しますという場合は最初から下記に気をつけて HTML を記述してください。

  • テキストは p 要素できちんと段落分けする。p 要素に入っていないテキストは無視される
  • img 要素は figure 要素でマークアップし、さらに p 要素内では使ってはいけない (figure 要素を p 要素内で使えないのは元々 HTML5 の仕様)
  • YouTube の埋め込みなど、iframe 要素も figure 要素でマークアップが必要。p 要素からも出さないといけない (YouTube の場合は <figure class="op-social"> を使用)
  • ul、ol 要素は使用できるが、リストの入れ子は不可 (入れ子になっていると正しく表示されない)
  • dl 要素は使用不可
  • table 要素や pre 要素も使用不可 (この辺の未対応要素を表示させる方法については後述)
  • cite 要素は figcaption 要素内以外では使用不可 (blockquote 要素内などで使用している場合は注意)
  • blockquote 要素に cite 属性が付いているとエラーになる
  • リンクや画像のパスはすべて絶対 URL で記述 (要するに src="/img/hoge.jpg" とかダメ)
  • 本文内で使える見出し要素は h1 と h2 のみ
  • 記事内で使用する画像の推奨サイズは 2048×2048 (ただし必須ではない)。画像サイズの上限は 8MB
  • style 属性で CSS を記述しても無視される
  • 独自に CSS は当てられないため、元記事で class をつけて見た目を変えていたりする箇所は再現不可
  • Twitter や Facebook、Instagram の埋め込みは、埋め込みコードを <figure class="op-social"><iframe> ~ </iframe></figure> で囲む必要がある

HTML のマークアップについてまとめると、

  • article 要素の直下 (直接の子要素) では、header、footer、aside、p、figure、blockquote、ul、ol、h1、h2 要素のみ使用可
  • header、footer 要素は特別な意味を持つのでそこに記述できる内容は決められている
  • figure 要素内で img、figcaption iframe 要素が使用可。figure 要素に class="op-****" を付与することで特定の用途を示せるようになっている
  • iframe 要素内では table、pre、script 要素なども使える (article 要素直下に書けない要素はこの中に書けばなんとかなるみたい)
  • ul、ol は入れ子にはできない (li 要素内に別のリストを入れるのはダメということ)
  • 上に書いた要素内 (例えば p 要素の中) で a 要素でリンクを張るのはもちろん問題なし。また、strong とか em とか code、span 要素など、HTML 4.01 などでいうインライン要素を使っている分には特に問題ないみたい (ただし、前述の通り cite 要素だけは別)
  • br 要素は無視される

細かく言うと他にもあるのですが、普段記事を書いていて関係しそうな箇所というと上記のような感じになります。実際のところ、この Blog のような技術系のネタが多い Blog には結構きつかったです。

pre 要素が使えない (後述しますが、実際には表示する方法があるので記事内には入れられるものの、ものすごく読みにくい) のとか、リストの入れ子も結構使っているので、その辺がダメって言われるとかなり大変。

ニュースサイトのような、本文内で p 要素以外には img 要素と a 要素程度しか使いませんみたいな記事しかないなら楽勝ですが、それ以外の場合は少し覚悟が必要です。

HTML の変換例

通常の Web ページ内で書かれるであろう HTML をインスタント記事用の HTML にすると下記のような感じになりますという例をいくつか。

マークアップ例 1

<!--before: よくある文章間に挿入される画像-->
<p><img alt="写真:写真の説明" src="https://example.com/article/01.jpg" width="1600" height="1200" /></p>

<!--after: figure 要素でマークアップ-->
<figure><img alt="写真:写真の説明" src="https://example.com/article/01.jpg" width="1600" height="1200" /></figure>

マークアップ例 2

<!--before: 文章の中画像が書かれてる場合は?-->
<p>テキスト <img alt="" src="https://example.com/icon.png" width="16" height="16" /> テキスト。</p>

<!--after: 下記のように figure 要素でマークアップしないといけないが、アイコンのようなものの場合はそのままでよいかも(画像が表示されなくなるだけ)-->
<p>テキスト</p>
<figure><img alt="" src="https://example.com/icon.png" width="16" height="16" /></figure>
<p>テキスト。</p>

マークアップ例 3

<!--before: YouTube の埋め込み-->
<p><iframe width="1280" height="720" src="https://www.youtube.com/embed/****" frameborder="0" allowfullscreen></iframe></p>

<!--after: figure 要素に class="op-social" をつけてマークアップ-->
<figure class="op-social"><iframe width="1280" height="720" src="https://www.youtube.com/embed/****" frameborder="0" allowfullscreen></iframe></figure>

マークアップ例 4

<!--before: Twitter の埋め込みツイート-->
<blockquote class="twitter-tweet">
  <p>Twitter の埋め込みツイート</p>— yoshiki kato (@burnworks) <a href="...">March 21, 2016</a>
</blockquote>

<!--after: figure 要素に class="op-social" をつけてさらに iframe でマークアップ-->
<figure class="op-social">
  <iframe>
    <blockquote class="twitter-tweet">
      <p>Twitter の埋め込みツイート</p>— yoshiki kato (@burnworks) <a href="...">March 21, 2016</a>
    </blockquote>
  </iframe>
</figure>

マークアップ例 5

<!--before: table 要素-->
<table>
  <tr>
    <th>・・・</th>
    <td>・・・</td>
  </tr>
</table>

<!--after: figure 要素に class="op-interactive" をつけてさらに iframe でマークアップ-->
<figure class="op-social">
  <iframe>
    <table>
      <tr>
        <th>・・・</th>
        <td>・・・</td>
      </tr>
    </table>
  </iframe>
</figure>
<!--ただし罫線も表示されないしとても見にくい。無理矢理感ある-->

広告の挿入について

インスタント記事内に広告を入れたい場合ですが、結構よくできていて、特定の指定さえしておけば、Facebook アプリがよきに計らってくれます。

任意の場所に広告を挿入したい場合

記事内の任意の箇所に広告を入れたい場合は、例えば記事の読み終わりに入れたければその場所に下記のように広告コードをそのまま入れておけば大丈夫です。

<!--Facebook 広告 (オーディエンスネットワーク) の場合-->
<figure class="op-ad">
  <iframe width="320" height="50" style="border:0;margin:0;" src="https://www.facebook.com/adnw_request?placement=****"></iframe>
</figure>
<!--AdSense の場合-->
<figure class="op-ad">
  <iframe width="320" height="100">
    <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
    <ins class="adsbygoogle"
         style="display:inline-block;width:320px;height:100px"
         data-ad-client="ca-pub-****"
         data-ad-slot="****"></ins>
    <script>
    (adsbygoogle = window.adsbygoogle || []).push({});
    </script>
  </iframe>
</figure>

自動で広告を配置してもらいたい場合

アプリ側でうまいこと本文の長さなどに応じて広告を自動挿入してくれます。まず head 要素内で広告自動配置機能を有効にするための指定を記述します。

<head>
  <meta charset="utf-8">
  <meta property="op:markup_version" content="v1.0">
  <meta property="fb:article_style" content="default">
  <meta property="fb:use_automatic_ad_placement" content="true">
</head>

下記の部分が該当します。この記述を省略した場合の初期値は false なので、true を明示してあげます。

<meta property="fb:use_automatic_ad_placement" content="true">

次に、今度は header 要素内で配置したい広告タグを設定します。

<body>
  <article>
    <header>
      ・・・省略・・・
      <section class="op-ad-template">
        <figure class="op-ad">
          <iframe src="..." width="320" height="50"></iframe>
        </figure>
        <figure class="op-ad op-ad-default">
          <iframe src="..." width="320" height="50"></iframe>
        </figure>
        <figure class="op-ad">
          <iframe src="..." width="320" height="50"></iframe>
        </figure>
      </section>
</header>
・・・省略・・・

<section class="op-ad-template"> ~ </section> 内に、必要な数だけ広告タグを記述します。もちろん、1つでも構いません。

そうすると、アプリが本文の長さなどを考慮しつつ、指定した広告のセットをいい具合に配置してくれます。

本文が長くて上の例のように指定した 3つの広告では足りないという場合は、op-ad-default を付与した広告タグが繰り返し使用されますので、特に重要な広告タグにこれをつけておくとよいみたい。

ただ、AdSense については、記事コンテンツを読み込んで、それにマッチする広告を配信する仕組みなので、アプリ内で読み込まれた場合に正しく広告が配信されるものなのですかね? そこだけ気になります。私が試した限りでは広告自体は配信されますが、コンテンツとマッチした内容にはならなかったので、現在は Facebook オーディエンスネットワークのみ使用しています。

関連記事の挿入について

関連記事は下記のようなフォーマットの ul 要素を、footer 要素内、あるいは article 要素内に配置することで表示させることができます。リストは最大 3記事まで。

<ul class="op-related-articles">
  <li><a href="http://example.com/article.html"></a></li>
  <li data-sponsored="true"><a href="http://example.com/sponsored-article.html"></a></li>
  <li><a href="http://example.com/another-article.html"></a></li>
</ul>

a 要素は空になりますので、注意してください。この表記があると、別途 「関連記事」 というセクションが記事の最下部に自動的に挿入され、ここにリストして記事へのリンクが表示されます。

記事広告の場合は、data-sponsored="true" を付与するようになっていますので、お金をもらって書いた記事についてはこれを明記しましょう。

その他 フォーマットの仕様

その他、細かい仕様は下記リンク先に記載されています。例えば複数の画像をまとめたスライドショーを表示するための記述方法や、ビデオファイルの埋め込みなどについても書かれていますので、そういう内容が記事内に含まれる場合は確認してみるとよいと思います。

実際に RSS フィードを生成

フォーマットがある程度理解できたところで、実際に RSS フィードを生成します。

なお、インスタント記事用に作った RSS フィードは、一度 Facebook 側で審査というか、完全に機械的なものだと思いますがフォーマットに問題がないかなどをチェックする 「レビュー」 を通さないといけません (24~48時間かかります)。そしてそのレビューには、最低 10件の記事が必要です。

ですから、CMS から RSS フィードを出力する際は、10件分の記事がフィード内に入るようにしましょう。

Movable Type でのテンプレート例

ちなみにこの Blog は Movable Type で運用されていますので、Movable Type のテンプレートだと下記のような感じになります。わかりやすいようにコメントを入れてあります。

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title><$mt:BlogName remove_html="1" encode_xml="1"$></title>
<link><$mt:BlogURL$></link>
<description><$mt:BlogDescription remove_html="1" encode_xml="1"$></description>
<language>ja-jp</language>
<lastBuildDate><$mt:EntryDate utc="1" format="%Y-%m-%dT%H:%M:%SZ"$></lastBuildDate>
<mt:Ignore>↓公開日で最新10件ではなく、更新日が新しい順で10件に(レビュー時は lastn="10" でもよいが、運用時はこうしておかないと更新された記事が RSS に入らないため / 更新頻度が高い場合は件数を調整)</mt:Ignore>
<mt:Entries limit="5" sort_by="modified_on">
<item>
  <title><$mt:EntryTitle remove_html="1" encode_xml="1"$></title>
  <link><$mt:EntryPermalink$></link>
  <mt:Ignore>↓各記事で重複しない一意な ID になるように</mt:Ignore>
  <guid>tag:<$mt:BlogHost$>:<$mt:EntryDate format="%Y-%m-%d"$>:<$mt:EntryID$></guid>
  <mt:Ignore>↓記事公開日</mt:Ignore>
  <pubDate><$mt:EntryDate utc="1" format="%Y-%m-%dT%H:%M:%SZ"$></pubDate>
  <mt:Ignore>↓記事の執筆者</mt:Ignore>
  <author>Yoshiki Kato</author>
  <mt:Ignore>↓記事のサマリー</mt:Ignore>
  <description><$mt:EntryExcerpt convert_breaks="0" remove_html="1" encode_xml="1"$></description>
  <content:encoded>

  <mt:Ignore>↓ここから記事の HTML↓</mt:Ignore>
  <![CDATA[
  <!DOCTYPE html>
  <html lang="ja" prefix="op: http://media.facebook.com/op#">
  <head>
  <meta charset="utf-8">
  <meta property="op:markup_version" content="v1.0">
  <mt:Ignore>↓スタイルの指定</mt:Ignore>
  <meta property="fb:article_style" content="default">
  <mt:Ignore>↓広告自動配置を true に</mt:Ignore>
  <meta property="fb:use_automatic_ad_placement" content="true">
  <link rel="canonical" href="<$mt:EntryPermalink$>">
  </head>
  <body>
  <article>

  <mt:Ignore>↓ここから header↓</mt:Ignore>
  <header>

  <mt:Ignore>↓カバー画像(カスタムフィールドで OGP 用画像を登録する仕様が前提)</mt:Ignore>
  <figure>
  <img src="<mt:If tag="EntryDataOgpimage"><mt:EntryDataOgpimageAsset lastn="1"><$mt:AssetURL$></mt:EntryDataOgpimageAsset><mt:Else><$mt:BlogURL$>img/ogp.png</mt:If>">
  <figcaption><$mt:EntryTitle remove_html="1" encode_xml="1"$></figcaption>
  </figure>

  <mt:Ignore>↓見出しとサマリーとキッカー</mt:Ignore>
  <h1><$mt:EntryTitle remove_html="1" encode_xml="1"$></h1>
  <h2><$mt:EntryExcerpt convert_breaks="0" remove_html="1" encode_xml="1"$></h2>
  <mt:Ignore>↓当初カテゴリを入れていたけれど他の記事とキッカーが重複しているとレビューで怒られたので無効にした</mt:Ignore>
  <mt:Ignore><h3 class="op-kicker"><$mt:EntryCategory$></h3></mt:Ignore>

  <mt:Ignore>↓執筆者情報</mt:Ignore>
  <address>
  <a rel="facebook" href="https://www.facebook.com/burnworks">Yoshiki Kato</a>
  </address>

  <mt:Ignore>↓公開日時と更新日時</mt:Ignore>
  <time class="op-published" dateTime="<$mt:EntryDate format="%Y-%m-%d" language="en"$>T<$mt:EntryDate format="%H:%M:%S"$><$mt:BlogTimezone$>"><$mt:EntryDate format="%x %X" language="en"$></time>
  <time class="op-modified" dateTime="<$mt:EntryModifiedDate format="%Y-%m-%d" language="en"$>T<$mt:EntryModifiedDate format="%H:%M:%S"$><$mt:BlogTimezone$>"><$mt:EntryModifiedDate format="%x %X" language="en"$></time>

  <mt:Ignore>↓広告タグ(Facebookの広告ネットワーク使用例 / AdSenseなども可能)</mt:Ignore>
  <figure class="op-ad">
  <iframe width="320" height="50" style="border:0;margin:0;" src="https://www.facebook.com/adnw_request?placement=****"></iframe>
  </figure>
  </header>
  <mt:Ignore>↑ここまで header↑</mt:Ignore>

  <mt:Ignore>↓ここから元の記事内にある HTML を色々変換する処理(面倒くさい)↓</mt:Ignore>
  <mt:Ignore>↓1. iframe 要素があったら <figure class="op-social">~</figure> で囲む(YouTube の埋め込み以外に iframe を使っていない前提)</mt:Ignore>
  <mt:SetVarBlock name="regex1a">/(<iframe.*?>.*?<\/iframe>)/g</mt:SetVarBlock>
  <mt:SetVarBlock name="regex1b"><figure class="op-social">\1</figure></mt:SetVarBlock>
  <mt:Ignore>↓2. img 要素があったら <figure>~</figure> で囲む(img にリンクが張られている場合も考慮)</mt:Ignore>
  <mt:SetVarBlock name="regex2a">/((<a.*?>)?<img.*?>(<\/a>)?)/g</mt:SetVarBlock>
  <mt:SetVarBlock name="regex2b"><figure>\1</figure></mt:SetVarBlock>
  <mt:Ignore>↓3. 先ほど変換した figure 要素が p 要素内にある場合は p 要素を削除</mt:Ignore>
  <mt:SetVarBlock name="regex3a">/<p.*?>(<figure.*?>.*?</figure>)<\/p>/g</mt:SetVarBlock>
  <mt:SetVarBlock name="regex3b">\1</mt:SetVarBlock>
  <mt:Ignore>↓4. h2 要素があったら h1 要素に変換</mt:Ignore>
  <mt:SetVarBlock name="regex4a">/<h2(.*)?>(.*)?<\/h2>/g</mt:SetVarBlock>
  <mt:SetVarBlock name="regex4b"><h1\1>\2</h1></mt:SetVarBlock>
  <mt:Ignore>↓5. h3~h6 要素があったらすべて h2 要素に変換</mt:Ignore>
  <mt:SetVarBlock name="regex5a">/<h[3-6](.*)?>(.*)?<\/h[3-6]>/g</mt:SetVarBlock>
  <mt:SetVarBlock name="regex5b"><h2\1>\2</h2></mt:SetVarBlock>
  <mt:Ignore>↓6. blockquote 要素に cite 属性が付いていたら削除</mt:Ignore>
  <mt:SetVarBlock name="regex6a">/<blockquote cite=\".*?\".*?>/g</mt:SetVarBlock>
  <mt:SetVarBlock name="regex6b"><blockquote></mt:SetVarBlock>
  <mt:Ignore>↓7. q 要素に cite 属性が付いていたら削除</mt:Ignore>
  <mt:SetVarBlock name="regex7a">/<q.*?>/g</mt:SetVarBlock>
  <mt:SetVarBlock name="regex7b"><q></mt:SetVarBlock>
  <mt:Ignore>↓8. cite 要素があったら削除してテキストのみに</mt:Ignore>
  <mt:SetVarBlock name="regex8a">/<cite>(.*)?<\/cite>/g</mt:SetVarBlock>
  <mt:SetVarBlock name="regex8b">\1</mt:SetVarBlock>
  <mt:Ignore>↑ここまで元の記事内にある HTML を色々変換する処理↑</mt:Ignore>

  <mt:Ignore>↓上で書いた変換処理を適用</mt:Ignore>
  <mt:Unless regex_replace="$regex1a","$regex1b" regex_replace="$regex2a","$regex2b" regex_replace="$regex3a","$regex3b" regex_replace="$regex4a","$regex4b" regex_replace="$regex5a","$regex5b" regex_replace="$regex6a","$regex6b" regex_replace="$regex7a","$regex7b" regex_replace="$regex8a","$regex8b">
  <$mt:EntryBody$>
  <$mt:EntryMore$>
  </mt:Unless>

  <mt:Ignore>↓ここから footer↓</mt:Ignore>
  <footer>

  <mt:Ignore>↓関連記事のリストを表示するための処理(別途記事テンプレートで関連記事リストを別途作っておいて読み込む / 「AllowFileInclude 1」 していないと動かない)</mt:Ignore>
  <mt:SetVarBlock name="includepath">[ここに読み込むファイルのパスをセットする記述]</mt:SetVarBlock>
  <$mt:Include file="$includepath"$>

  <mt:Ignore>↓ちょっと表示が気になったので念のため注釈(ブラウザで見ろって本末転倒な気もするけど)。そもそも無理に全ページをインスタント記事対応させる必要もない</mt:Ignore>
  <aside>
  <p>インスタント記事の仕様により、表組みなどを含む記事が一部読みにくい場合があります。その場合は元記事( <$mt:EntryPermalink$> )をブラウザでご覧ください。</p>
  </aside>

  <mt:Ignore>↓署名。small 要素内に記述</mt:Ignore>
  <small>Yoshiki Kato @burnworks</small>
  </footer>
  <mt:Ignore>↑ここまで footer↑</mt:Ignore>

  </article>
  </body>
  </html>
  ]]>
  <mt:Ignore>↑ここまで記事の HTML↑</mt:Ignore>

  </content:encoded>
</item>
</mt:Entries>
</channel>
</rss>

ちなみに私の名前が入っている署名や著者名のところは当然書き換えてください。また、広告タグも当然ですが書き換えが必要。また、一部カスタムフィールドを使ったり、他のテンプレートを読み込む前提の処理もそのまま入れてありますが、その辺はソースコードを見て自前でカスタマイズしてください。

それから、regex_replace モディファイアを使用した変換部分は、実際に書かれている HTML にあわせて調整が必要だと思います。例えば table 要素の変換とか、pre 要素の変換も必要かもしれませんし、iframe 要素を YouTube の埋め込み以外でも使用している場合は少し正規表現を変更する必要があるかもしれません。

この辺はモディファイアだと制約もあるのでプラグインとかでやった方が確実なんですけどね。SixApart さんが下記にインスタント記事用 RSS フィードを生成するプラグインを公開してくれていますので、それを使ってみるのもよいと思いますが、足りない処理は自分でなんとかしないといけません。

WordPress を使っている場合は、下記の通り Facebook が WordPress と共同で開発したプラグインが公開されていますので、それを使ってみるのもよいと思いますが、私は実際に使ってみていないのでどの程度自動で処理してくれるのかわかりません。

RSS フィードを Facebook 管理画面から登録

インスタント記事の設定、後半戦です。RSS フィードが正しく生成できたら、レビューを申請します。

Facebook ページのインスタント記事管理画面に戻り、「Tools」 エリアにある 「Production RSS Feed」 の項目を開き、生成したインスタント記事用 RSS フィードの URL を入力して 「保存」 を押し、登録します。

インスタント記事用 RSS フィードを登録

RSS フィードが正しく読み込まれると、「Initial Setup」 エリアの 「Step 2: Submit For Review」 で、「Submit for Review」 ボタンが押せるようになると思いますので、押します。

インスタント記事用 RSS フィードのレビューを申請

申請が受け付けられると、画面が切り替わり、レビュー完了までしばらく待ってねという表示に変わると思います。

レビューを申請が完了した状態

レビューには 24~48時間かかるので、フィードはしばらく放置です。

インスタント記事の見た目を調整

インスタント記事のデザイン調整は Facebook 管理画面にあるスタイルエディタから行います。インスタント記事管理画面の 「Tools」 エリアにある 「Styles」 の項目を開くと、初期状態で 「default」 というスタイルが設定されていると思います。これをいじってもよいのですが、残しておきたい場合はその下にある 「+ Add Style」 を押すと新規スタイルが作成できます。

インスタント記事のデザインを調整

ここで、各エリアのカラーやフォント (フォントと言っても英語前提になってしまっているので選べるフォントが限られますが)、ロゴ画像をアップロードすることができます。

左上のスタイルの名前を自分で管理しやすいように変更して、それを RSS フィード内で指定すると、そのスタイルが適用されることになります。

先のサンプルソース内では下記のように 「default」 が指定されていたと思いますが、ここの名前を変えることで、適用するデザインを選択できます。この指定は記事ごとに入るので、記事ごとに別のスタイルを当てることもできると思います (実際に試していないのでわかりませんが)。

<meta property="fb:article_style" content="default">

デザインの設定については下記に日本語のドキュメントがきちんと用意されていますので、これを参考にしながらいじってみるとよいでしょう。

作成したスタイルを適用したい場合は下記のように content 属性値を変更します。

<meta property="fb:article_style" content="your-style-name">

インスタント記事の確認

では実際にどういう形で記事が表示されるのかを確認します。まず、手持ちのスマートフォンに 「Facebookページマネージャ」 をダウンロードしてください。

インストール後、ログインすると管理している Facebook ページが表示されると思いますが、「その他」 メニューに 「インスタント記事」 という項目がありますので、そこをタップすると、

Facebook ページマネージャからインスタント記事を選択

下記のようにインスタント記事が実際に確認出来ます。

インスタント記事のデザインを調整

上部にタブがあって、「プロダクション」「開発」「例」 と選択できるようになっていると思いますが、「例」 を開くと、サンプルインスタント記事が見られますので、参考にしてみるとよいかと。

「プロダクション」 は先ほどの手順で 「Production RSS Feed」 に RSS フィードを登録したので表示されていると思いますが、「開発」 は 「Development RSS Feed」 に登録された RSS フィードの内容が表示されます。

開発用と分けて作業を進めたい場合は便利です。

ちなみに、レビューが完了していない状態だと、インスタント記事は一般には公開されていない状態です。管理者だけが確認のために閲覧できているという状態ですね。

RSS フィードを更新したのに反映されない場合

RSS フィードのテンプレートを修正したり、前述したスタイルエディタで設定を変えたけれど、実際にアプリでインスタント記事を見ても変更が反映されないという場合は、記事の更新日が変更されていないと再読込されないので確認してみるとよいと思います。

先に紹介したサンプルソースで言うと下記の部分ですね。

<time class="op-modified" dateTime="2016-04-17T20:51:01+09:00">April 17, 2016  8:51 PM</time> <

これが更新されていない記事、あるいは 24時間以上前に更新された記事の場合は再読込されませんので、必要に応じて更新します(フィード自体は 1時間おきに Facebook のクローラーが取得していくそうです)。

レビューで怒られたときは

レビュー結果がでて、もし RSS フィードの内容にエラーがあると下記のように、「ここがおかしいから直しなさい」 という表示が出ます。

レビュー結果でエラーが出た例

各エラーを開くと、「ここがダメだよ」 という点をソースコード上に表示してくれますので、すべて修正しましょう。

レビュー結果でエラー箇所表示例

間違いなく修正できたことを確認したら、「Resubmit for Review」 を押して再申請します。再申請したらまた 24~48時間、レビュー完了まで待ちます。

レビュー完了、実際に記事を配信開始

無事レビューが完了すると、インスタント記事を公開することができます。管理画面のインスタント記事設定画面を見ると、「Step 3」 で記事の公開をスタートすることができるようになります。

RSS フィードによるオートパブリッシュが初期段階では 「Off」 になっていると思いますので、これを 「Auto-Publish On」 に変更しましょう。これで、新しい記事が追加されて RSS フィードが更新されると、それを自動的に取得してインスタント記事が公開されます。

Facebook インスタント記事の公開開始

インスタント記事公開状態の確認など

Facebook ページに PC からアクセスし、ヘッダメニューの 「投稿ツール」 を開くと、「インスタント記事」 の項目があると思います。

Facebook インスタント記事の公開状態確認と変更

公開されている記事はステータスの項目が 「ライブ」 になっていると思います。

上の画像にもありますが、エラーっぽいアイコンが付いているものは、インスタント記事の HTML 内に何らかエラーがあるものになりますので、該当記事の 「編集」 を押すと、エラー内容が表示されます。

重大なエラーがある場合は赤色でエラー内容が表示され、インスタント記事自体も 「未公開」 の状態になっていると思います。重大なエラーについては修正されるまでインスタント記事を公開することができませんので、問題の箇所を修正して、RSS フィードを更新しましょう。

軽度なエラーの場合は、オレンジ色でエラー内容が表示されますが、インスタント記事は公開された状態になります。

すでに公開されているインスタント記事を何らかの理由で非公開にしたい場合は記事にチェックを入れて上部のプルダウンメニューから 「Unpublish (なぜかここだけ英語)」 を選択すれば非公開にできます。

Facebook インスタント記事を非公開に

この投稿ツールでの操作方法等については公式ドキュメントにも説明がありますので下記もあわせて確認してみてください。

すべての記事をインスタント記事で公開する必要はないと思います。当 Blog でもソースコードが多かったり、インスタント記事での閲覧に向かない記事はインスタント記事を非公開にして通常サイトを表示するようにしています。

この辺は記事の内容に応じてうまく切り分けて運用すればよいと思われます。

実際にインスタント記事を表示

あとは、Facebook ページのタイムラインに記事を投稿してみましょう。例えば下記のように Blog で更新した記事を Facebook ページに投稿します。

Facebook ページでの投稿表示例

インスタント記事に対応していない場合は、投稿をタップすると、元の記事ページに遷移してそこで記事を読むという流れだったと思いますが、投稿した URL にインスタント記事が存在すると、元記事には遷移せずインスタント記事が表示されます。これによってページ読み込みが数倍速くなるというわけですね。

記事へのリンクをタップするとインスタント記事が表示される

インスタント記事が表示されるのは下記のバージョン以降の Facebook アプリを使っている場合のみです。

  • iPhone Facebook for iPhone Ver.30.0 / iOS 7.0 以降
  • Android Facebook for Android Ver.57 / Android Jelly Bean 以降

ちなみに当 Blog の Facebook ページは下記にあります。


さて、長々と解説してきましたが、インスタント記事の配信を始めてみたいという方の参考なれば幸いです。途中でも書いた通り、本文と写真の組み合わせのみなど、かなり単純な記事の構造でないと HTML マークアップの制約から大変なことが多いかもしれません。

その場合は、面倒ですがインスタント記事向けに元記事を再編集して、別途 RSS フィードだけを更新する方が無理に変換処理でなんとかするより楽かもしれませんね。

逆に言えば記事内に複雑な HTML が入らない Blog やメディアサイトであれば、比較的簡単にインスタント記事に対応させることができると思います。

追記

関連記事

記事をここまで御覧頂きありがとうございます。
この記事が気に入ったらサポートしてみませんか?