【WordPress】投稿本文のSNS埋め込みをAMP対応させる方法

【WordPress】投稿本文のSNS埋め込みをAMP対応させる方法

まるでそこにあったかのように爆速でWEBページを表示してくれるAMPフォーマット

だんだんと仕様追加されてできることが増えてきましたが、まだまだ既存のサイトをAMPに対応するにはそれなりの苦労が必要です。

なかでも、今回SNSの埋め込みをAMP対応させるコードを書いたときにそれなりに苦労したので備忘録的にまとめておきます。

SNS埋め込みをAMP対応させる

よっひー(@yosiakatsuki)です。

仕様の厳しいAMPフォーマットでもTwitterの埋め込みがいい感じに見たい!

という願いを叶えるために、ちゃんとAMP側でSNSの埋め込みに関する仕様がいろいろとまとめられています。

WordPressの投稿内に書かれたSNSの埋め込みをAMPに対応する記述に置換するためにいろいろと頭を悩ませた部分があったので、その備忘録です。

投稿本文のSNS埋め込みをAMP対応させるコード

投稿本文内のSNS関連の埋め込みを置換するためのコードはこちら↓

  function ys_amp_replace_sns($content) {

    // Twitter >>>>
    $pattern = '/<p>https:\/\/twitter.com\/.*?\/status\/(.*?)".*?<\/p>/i';
    $append = '<p><amp-twitter width=486 height=657 layout="responsive" data-tweetid="$1"></amp-twitter></p>';
    $content = preg_replace($pattern, $append, $content);

    // scriptにwpautopが効くパターン
    $pattern = '/<blockquote class="twitter-tweet".*?>.*?<a href="https:\/\/twitter.com\/.*?\/status\/(.*?)">.*?<\/blockquote>.*?<script async src="\/\/platform.twitter.com\/widgets.js" charset="utf-8"><\/script><\/p>/is';
    $append = '<p><amp-twitter width=486 height=657 layout="responsive" data-tweetid="$1"></amp-twitter></p>';
    $content = preg_replace($pattern, $append, $content);

    // scriptにwpautopが効かなかったパターン
    $pattern = '/<blockquote class="twitter-tweet".*?>.+?<a href="https:\/\/twitter.com\/.*?\/status\/(.*?)">.+?<\/blockquote>.*?<script async src="\/\/platform.twitter.com\/widgets.js" charset="utf-8"><\/script>/is';
    $append = '<p><amp-twitter width=486 height=657 layout="responsive" data-tweetid="$1"></amp-twitter></p>';
    $content = preg_replace($pattern, $append, $content);

    // blockquoteのみパターン
    $pattern = '/<blockquote class="twitter-tweet".*?>.*?<a href="https:\/\/twitter.com\/.*?\/status\/(.*?)".*?<\/blockquote>/is';
    $append = '<p><amp-twitter width=486 height=657 layout="responsive" data-tweetid="$1"></amp-twitter></p>';
    $content = preg_replace($pattern, $append, $content);
    // <<<< Twitter

    // Instagram >>>>
    // scriptにwpautopが効くパターン
    $pattern = '/<blockquote class="instagram-media".+?"https:\/\/www.instagram.com\/p\/(.+?)\/".+?<\/blockquote>.*?<script async defer src="\/\/platform.instagram.com\/.+?\/embeds.js"><\/script><\/p>/is';
    $append = '<amp-instagram layout="responsive" data-shortcode="$1" width="400" height="400" ></amp-instagram>';
    $content = preg_replace($pattern, $append, $content);

    // scriptにwpautopが効かなかったパターン
    $pattern = '/<blockquote class="instagram-media".+?"https:\/\/www.instagram.com\/p\/(.+?)\/".+?<\/blockquote>.*?<script async defer src="\/\/platform.instagram.com\/.+?\/embeds.js"><\/script>/is';
    $append = '<amp-instagram layout="responsive" data-shortcode="$1" width="400" height="400" ></amp-instagram>';
    $content = preg_replace($pattern, $append, $content);

    // blockquoteのみパターン
    $pattern = '/<blockquote class="instagram-media".+?"https:\/\/www.instagram.com\/p\/(.+?)\/".+?<\/blockquote>/is';
    $append = '<amp-instagram layout="responsive" data-shortcode="$1" width="400" height="400" ></amp-instagram>';
    $content = preg_replace($pattern, $append, $content);
    // <<<< Instagram

    // YouTube
    $pattern = '/<iframe[^>]+?src="https:\/\/www.youtube.com\/embed\/(.+?)(\?feature=oembed)?".*?><\/iframe>/is';
    $append = '<amp-youtube layout="responsive" data-videoid="$1" width="480" height="270"></amp-youtube>';
    $content = preg_replace($pattern, $append, $content);

    // vine
    $pattern = '/<iframe[^>]+?src="https:\/\/vine.co\/v\/(.+?)\/embed\/simple".+?><\/iframe>/is';
    $append = '<amp-vine data-vineid="$1" width="600" height="600" layout="responsive"></amp-vine>';
    $content = preg_replace($pattern, $append, $content);

    // Facebook post
    $pattern = '/<iframe[^>]+?src="https:\/\/www\.facebook\.com\/plugins\/post\.php\?href=(.*?)&.+?".+?><\/iframe>/is';
    $content = preg_replace_callback(
                  $pattern
                  , function ($m) {
                      return '<amp-facebook width=486 height=657 layout="responsive" data-href="'.urldecode($m[1]).'"></amp-facebook>';
                    }
                  , $content);

    // Facebook video
    $pattern = '/<iframe[^>]+?src="https:\/\/www\.facebook\.com\/plugins\/video\.php\?href=(.*?)&.+?".+?><\/iframe>/is';
    $content = preg_replace_callback(
                  $pattern
                  , function ($m) {
                      return '<amp-facebook width=552 height=574 layout="responsive" data-embed-as="video" data-href="'.urldecode($m[1]).'"></amp-facebook>';
                    }
                  , $content);


    return $content;
  }

引数$contentには投稿本文のテキストを渡してあげてください。(例:$post->post_content

上記関数で以下のSNSの埋め込みコードをAMPに対応させています。

  • Twitter
  • Instagram
  • YouTube
  • vine
  • Facebook

基本的には正規表現置換で、置換後のAMP用のタグ内で使用する必要がある部分(例:ツイートID)をグループ化させて再利用する方法で変換しています。

FacebookだけはAMP用タグで必要なURLがもとのiframeのsrc内でURLエンコードされてしまっている為、preg_replace_callbackを使って該当部分をデコードしています。

最初、マッチパターンの修飾子で/eを使おうと思ったらPHP 7で廃止になっているのでやめました…

Twitter、Instagramについては、単純に</script>まで置換するだけだと余分に</p>だけが残ったりと不思議なことになるので微調整しています。

AMPで必要なjsを読み込むための分岐

投稿本文内のSNS埋め込み用のタグをAMPに置換しただけではまだ対応完了にはなりません。

それぞれのSNSに合わせたAMP用のスクリプトを読み込ませる必要があります。

ただ、「とにかく必要そうなスクリプトを読み込ませておけばいい」というわけではなく、必要なものだけ読み込ませる必要があります。

(記事執筆時点(2017/01/29)では、必要のないスクリプトを読み込んでいてもエラーにはなっていませんが、「これは今後エラーとなる可能性があります。」という警告が表示されています)

…ということで、投稿本文のタグの置換とともに下記のコードでhead内に必要なscriptタグを出力していきます。

function ys_amp_the_amp_script() {
  global $post;

  $html = '';
  $content = $post->post_content;

  // Twitter
  $pattern = '/https:\/\/twitter.com\/.*?\/status\/(.*?)"/i';
  if(preg_match($pattern,$content,$matches) === 1){
    $html .= '<script async custom-element="amp-twitter" src="https://cdn.ampproject.org/v0/amp-twitter-0.1.js"></script>'.PHP_EOL;
  }

  // Instagram
  $pattern = '/https:\/\/www.instagram.com\/p\/(.+?)\/"/i';
  if(preg_match($pattern,$content,$matches) === 1){
    $html .= '<script custom-element="amp-instagram" src="https://cdn.ampproject.org/v0/amp-instagram-0.1.js" async></script>'.PHP_EOL;
  }

  // YouTube
  $pattern = '/<iframe.+?src="https:\/\/www.youtube.com\/embed\/(.+?)(\?feature=oembed)?".*?><\/iframe>/i';
  if(preg_match($pattern,$content,$matches) === 1){
    $html .= '<script async custom-element="amp-youtube" src="https://cdn.ampproject.org/v0/amp-youtube-0.1.js"></script>'.PHP_EOL;
    $content = preg_replace($pattern, '', $content);
  }

  // vine
  $pattern = '/<iframe[^>]+?src="https:\/\/vine.co\/v\/(.+?)\/embed\/simple".+?><\/iframe>/i';
  if(preg_match($pattern,$content,$matches) === 1){
    $html .= '<script async custom-element="amp-vine" src="https://cdn.ampproject.org/v0/amp-vine-0.1.js"></script>'.PHP_EOL;
    $content = preg_replace($pattern, '', $content);
  }

  // Facebook
  $pattern = '/<iframe[^>]+?src="https:\/\/www\.facebook\.com\/plugins\/(.*?)&.+?".+?><\/iframe>/i';
  if(preg_match($pattern,$content,$matches) === 1){
    $html .= '<script async custom-element="amp-facebook" src="https://cdn.ampproject.org/v0/amp-facebook-0.1.js"></script>'.PHP_EOL;
    $content = preg_replace($pattern, '', $content);
  }

  // iframe
  $pattern = '/<iframe/i';
  if(preg_match($pattern,$content,$matches) === 1){
    $html .= '<script async custom-element="amp-iframe" src="https://cdn.ampproject.org/v0/amp-iframe-0.1.js"></script>'.PHP_EOL;
  }

  echo $html;
}

iframeの判断より先にYouTube,vine,Facebookの判断をし、それぞれのパターンにマッチする文字列は削除しておきます。

そうしないと、YouTube,vine,Facebookがあったときに必ずiframe用のスクリプトを読み込んでしまい、不要なスクリプトを読み込んでいる…と警告されてしまいます…

まとめ

AMPは仕様の追加・変更が激しいので、ちょっと前までOKだったことがいつの間にか警告になっていたりします…(その逆で、この前エラーだったのに今はエラーじゃなくなった。ということもあります。)

Google Search Consoleでエラーが無いかマメに確認していく必要がありますね…

疲れる。

参考

よっしーのひとこと

よっひー

こっそりコツコツ作っている一般公開しようと思っているテーマに実装するために正規表現と戦いました。

春までには仕上げたい。

ではまた。