Twitter/Facebookへのページシェアでコンテンツを埋め込む(OGP)¶
注釈
OGPを生成する機能のSphinx本体への組み込みが PR#7974 で検討されましたが、 sphinxext-opengraph 拡張を利用すれば良さそうなため見送られました。
Sphinx-users.jp 自体のOGP生成も独自実装(本ページで紹介しているコード)から、sphinxext-opengraphに切り替えました。差分はこちらです: https://github.com/sphinxjp/sphinx-users.jp/pull/103
概要¶
Sphinxで作成したページのURLをTwitterやFacebookといったSNSに投稿することがあります。このとき、そのページの内容数行と画像が投稿内容に自動的に表示されれば、その投稿を見た人が内容により興味を持ってくれるかもしれません。
このような、SNS投稿にコンテンツ内容を表示するための仕組みとして、 Open Graph protocol (OGP) という仕組みがあります。OGPは、HTMLのメタタグを適切に持たせることで、投稿先SNS等が表示するべきコンテンツ内容を把握し、その情報を表示してくれる仕組みです。

図 7 OGP対応ページの投稿¶
この拡張が出力するmetaタグ¶
この拡張は、以下のHTMLタグを出力します。
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="@sphinxjp" />
<meta property="og:site_name" content="Python製ドキュメンテーションビルダー、Sphinxの日本ユーザ会">
<meta property="og:title" content="Twitter/Facebookへのページシェアでコンテンツを埋め込む(OGP)">
<meta property="og:description" content="Sphinxで作成したページのURLをTwitterやFacebookといったSNSに投稿することがあります。このとき、そのページの内容数行と画像が投稿内容に自動的に表示されれば、その投稿を見た人が内容により興味を持ってくれるかもしれません。このような、SNS投稿にコンテンツ内容を表示するための仕組みとして、Open Graph protocol (OGP)という仕組みがあります。OGPは、HTMLのメタタグを適切に持たせることで、投稿先SNS等が表示するべきコンテンツ内容を把握し、その情報を表示してくれる仕組み...">
<meta property='og:url' content="http://sphinx-users.jp/cookbook/ogp/index.html">
<meta property="og:image" content="http://sphinx-users.jp/_images/sphinx-ogp-no-image.png">
注釈
このタグが出力されるためには、Sphinxテーマで使っているテンプレートが metatags
を出力している必要があります。Sphinx組み込みのテーマ、alabaster, sphinx_rtd_theme はこの出力に対応しています。
コード¶
以下の内容をそれぞれのファイル名でSphinxプロジェクトに組み込んでください。
import sys
import os
sys.path.append(os.path.abspath('_ext'))
extensions = [
'ogtag',
]
og_site_url = 'http://sphinx-users.jp/'
og_twitter_site = '@sphinxjp'
conf.py
の og_site_url
には、HTML公開先のドキュメントルートのURLを記載します。
from docutils import nodes
from sphinx import addnodes
from urllib.parse import urljoin
class Visitor:
def __init__(self, document):
self.document = document
self.text_list = []
self.images = []
self.n_sections = 0
def dispatch_visit(self, node):
# toctreeは飛ばす
if isinstance(node, addnodes.compact_paragraph) and node.get('toctree'):
raise nodes.SkipChildren
# 画像を収集
if isinstance(node, nodes.image):
self.images.append(node)
# 3つ目のセクションまではテキスト収集する
if self.n_sections < 3:
# テキストを収集
if isinstance(node, nodes.paragraph):
self.text_list.append(node.astext())
# セクションに来たら深さを追加
if isinstance(node, nodes.section):
self.n_sections += 1
def dispatch_departure(self, node):
pass
def get_og_description(self):
# TODO: 何文字までが良いのか?
text = ' '.join(self.text_list)
if len(text) > 200:
text = text[:197] + '...'
return text
def get_og_image_url(self, page_url):
# TODO: 必ず最初の画像で良いのか
if self.images:
return urljoin(page_url, self.images[0]['uri'])
else:
return None
def get_og_tags(context, doctree, config):
# page_url
site_url = config['og_site_url']
page_url = urljoin(site_url, context['pagename'] + context['file_suffix'])
# collection
visitor = Visitor(doctree)
doctree.walkabout(visitor)
# og:description
og_desc = visitor.get_og_description()
# og:image
og_image = visitor.get_og_image_url(page_url)
## OGP
tags = '''
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="{cfg[og_twitter_site]}" />
<meta property="og:site_name" content="{ctx[shorttitle]}">
<meta property="og:title" content="{ctx[title]}">
<meta property="og:description" content="{desc}">
<meta property='og:url' content="{page_url}">
'''.format(ctx=context, desc=og_desc, page_url=page_url, cfg=config)
if og_image:
tags += '<meta property="og:image" content="{url}">'.format(url=og_image)
return tags
def html_page_context(app, pagename, templatename, context, doctree):
if not doctree:
return
context['metatags'] += get_og_tags(context, doctree, app.config)
def setup(app):
app.add_config_value('og_site_url', None, 'html')
app.add_config_value('og_twitter_site', None, 'html')
app.connect('html-page-context', html_page_context)
return {
'version': '0.1',
'parallel_read_safe': True,
'parallel_write_safe': True,
}
Twitterでの追加手順¶
Twitterの場合、ogタグのあるページを検証サイトに入力して、承認してもらう必要があります。詳しくは以下のページにある「検証ツールでURLを実行して申請」を参照してください。