かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

WordPress OGP 情報を自前で出力してみる

WordPress で OGP の情報を出力するには All in One SEO などのプラグインを使えば実現できるのですが、WordPress からしばらく離れていたこともあり WordPress 独特のプラグインGitHub にない場合も多くスター数やどれが現段階でのベストプラクティスなの判断できない・セキュリティの問題がどうなっているのか判らないという事があり素振りも兼ねて自前で実装してみたのでメモ

OGP に必要なメタタグ

<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# article: http://ogp.me/ns/article#">
<title>ページのタイトル</title>
<meta property="og:site_name" content="サイト名" />
<meta property="og:title" content="ページのタイトル" />
<meta property="og:type" content="ページの種類" />
<meta property="og:url" content="ページのURL" />
<meta property="og:image" content="サムネイル画像のURL" />
<meta property="og:description" content="ページのディスクリプション" />
<meta property="fb:app_id" content="App-ID(15文字の半角数字)" /> <!-- for Facebook -->
<meta name="twitter:card" content="Twitterカードの種類" /> <!-- for Twitter -->

cf. Facebook・TwitterのOGP設定方法まとめ|ferret

仕様

  • WordPress: v6.0
  • og:title … 現在のページのタイトル
  • og:typewebsite, 投稿の場合は article にする
  • og:url … 現在のページの URL
  • og:image … 投稿、固定ページでサムネイルがあればサムネイル。なければデフォルト画像。
  • og:site_name … 固定値 (サイト名)
  • og:description … 抜粋があれば抜粋。なければ本文から生成。それもなければデフォルト値
  • fb:app_idFacebook のアプリID なので固定値
  • twitter:card … 投稿の時は summary, 固定ページの場合は summary_large_image

※ コードを見やすくするために冗長に書いています

og:title 現在のページのタイトルを取得する

ページのタイトルを return する wp_get_document_title() を使って取得する
固定値のサイト名は get_bloginfo('name')管理画面 > 一般 > サイトのタイトル に指定されている値にする

<?php // functions.php
function mt_ogp() {
  $siteName = get_bloginfo('name');
  // ページタイトル
  $title = wp_get_document_title();

$ogp = <<< EOM
<meta property="og:site_name" content="{$siteName}" />
<meta property="og:title" content="{$title}" />
EOM;
  
  echo $ogp;
}

タイトル自体のカスタマイズは pre_get_document_title のようなフィルターを使うことで head 内の title と og:title を同じにすることができる

cf.

og:type ページのタイプ

website, 投稿の場合は article にする

is_singular() は投稿ページ以外に固定ページ is_page(), 添付ファイルページ is_attachment() を含むので is_single() を使うのが良さそう

<?php // functions.php
function mt_ogp() {
  $siteName = get_bloginfo('name');
  // ページタイトル
  $title = wp_get_document_title();
  // ページタイプ
  $pageType = 'website';
  if ( is_single() ) {
    $pageType = 'article';
  }

$ogp = <<< EOM
<meta property="og:site_name" content="{$siteName}" />
<meta property="og:title" content="{$title}" />
<meta name="og:type" content="{$ogpType}">
EOM;
  
  echo $ogp;
}

og:url 現在のページの URL

WordPress の URL は global の $post などを使って取得することができるが、投稿がない場合やカテゴリーの投稿が 0 件の時 $postNULL になったり、アーカイブページの $postアーカイブに含まれる最初の投稿だったりで分岐や条件分けがかなり複雑になってしまうので $_SERVER を使って現在の URL を取得するようにした

<?php // functions.php
function mt_ogp() {
  $siteName = get_bloginfo('name');
  // ページタイトル
  $title = wp_get_document_title();
  // ページタイプ
  $pageType = 'website';
  if ( is_single() ) {
    $pageType = 'article';
  }
  // 現在の URL
  $permalink = (is_ssl() ? 'https' : 'http') . '://' . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];

$ogp = <<< EOM
<meta property="og:site_name" content="{$siteName}" />
<meta property="og:title" content="{$title}" />
<meta name="og:type" content="{$ogpType}">
<meta property="og:url" content="{$permalink}" />
EOM;
  
  echo $ogp;
}

og:image

投稿、固定ページでサムネイルがあればサムネイル。なければデフォルト画像。

サムネイルを設定できるページは is_singular() (is_single() + is_page() + is_attachment()) なので、これが true の時にサムネイルの有無をチェックする
サムネイル画像の URL は wp_get_attachment_image_src($attachment_id, $size); で取得できる。デフォルトでは thumbnail が取得されるので OGP なら largefull を指定すれば良さそう

<?php // functions.php
define('OGP_IMAGE', get_home_url() . "/ogp.png");
function mt_ogp() {
  global $post;
  $siteName = get_bloginfo('name');
  // ページタイトル
  $title = wp_get_document_title();
  // ページタイプ
  $pageType = 'website';
  if ( is_single() ) {
    $pageType = 'article';
  }
  // 現在の URL
  $permalink = (is_ssl() ? 'https' : 'http') . '://' . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
  // OGP Image
  $ogpImage = OGP_IMAGE;
  if ( is_singular() ) {
    $thumbnail = wp_get_attachment_image_src(
      get_post_thumbnail_id($post->ID), 'full'
    );
    $ogpImage = $thumbnail[0] ?: OGP_IMAGE;
  }

$ogp = <<< EOM
<meta property="og:site_name" content="{$siteName}" />
<meta property="og:title" content="{$title}" />
<meta name="og:type" content="{$ogpType}">
<meta property="og:url" content="{$permalink}" />
<meta property="og:image" content="{$ogpImage}" />
EOM;
  
  echo $ogp;
}

cf. WordPress アップロードした画像を width, height 属性無しで取得したい - かもメモ

og:description ディスクリプション

抜粋があれば抜粋。なければ本文から生成。それもなければデフォルト値

抜粋は global オブジェクトの $post から $post->post_excerpt, 本文は $post->post_content で取得できる。本文の場合はタグの除去を行う必要がある
アーカイブページや 404 ページ、検索結果などはデフォルト値を返すようにする

<?php // functions.php
define("OGP_IMAGE", get_home_url() . "/ogp.png");
define("DESCRIPTION", "デフォルトのディスクリプション");
// $post から description を返す関数
function get_my_descriptiom_by_post($post, $limit = 140, $more = '...') {
  $summary = $post->post_excerpt;
  if ( empty($summary) ) {
    $content = apply_filters('the_content', $post->post_content);
    // タグの除去
    $summary = strip_tags($content);
    $summary = str_replace(array("\r\n","\n","\r"), ''
  }

  if ( empty($summary) ) { return NULL; }

  $description = wp_trim_words($summary, $limit, $more);
  return $description; 
}

function mt_ogp() {
  global $post;
  $siteName = get_bloginfo('name');
  // ページタイトル
  $title = wp_get_document_title();
  // ページタイプ
  $pageType = 'website';
  if ( is_single() ) {
    $pageType = 'article';
  }
  // 現在の URL
  $permalink = (is_ssl() ? 'https' : 'http') . '://' . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
  // OGP Image
  $ogpImage = OGP_IMAGE;
  if ( is_singular() ) {
    $thumbnail = wp_get_attachment_image_src(
      get_post_thumbnail_id($post->ID), 'full'
    );
    $ogpImage = $thumbnail[0] ?: OGP_IMAGE;
  }
  // description
  $description = DESCRIPTION;
  if ( is_singular() ) {
    $description = get_my_descriptiom_by_post($post);
  }
  if ( empty($description) || empty($post) || is_404() ) {
    $description = DESCRIPTION;  
  }

$ogp = <<< EOM
<meta property="og:site_name" content="{$siteName}" />
<meta property="og:title" content="{$title}" />
<meta name="og:type" content="{$ogpType}">
<meta property="og:url" content="{$permalink}" />
<meta property="og:image" content="{$ogpImage}" />
<meta property="og:description" content="{$description}" />
EOM;
  
  echo $ogp;
}

Facebook fb:app_id, Twitter twitter:card 用の設定

fb:app_idFacebook で取得するアプリの ID なので固定値を使えば OK twitter:card は 投稿の時は summary, 固定ページの場合は summary_large_image にする

<?php // functions.php
define("OGP_IMAGE", get_home_url() . "/ogp.png");
define("DESCRIPTION", "デフォルトのディスクリプション");
define("FACEBOOK_APP_ID", "APP ID");
// 略
function mt_ogp() {
  global $post;
  $siteName = get_bloginfo('name');
  // ページタイトル
  $title = wp_get_document_title();
  // ページタイプ
  $pageType = 'website';
  if ( is_single() ) {
    $pageType = 'article';
  }
  // 現在の URL
  $permalink = (is_ssl() ? 'https' : 'http') . '://' . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
  // OGP Image
  $ogpImage = OGP_IMAGE;
  if ( is_singular() ) {
    $thumbnail = wp_get_attachment_image_src(
      get_post_thumbnail_id($post->ID), 'full'
    );
    $ogpImage = $thumbnail[0] ?: OGP_IMAGE;
  }
  // description
  $description = DESCRIPTION;
  if ( is_singular() ) {
    $description = get_my_descriptiom_by_post($post);
  }
  if ( empty($description) || empty($post) || is_404() ) {
    $description = DESCRIPTION;  
  }
  // Facebook App ID
  $fbAppID =  FACEBOOK_APP_ID;
  // Twitter card
  $cardType = 'summary_large_image';
  if ( is_single() ) {
    $cardType = 'summary';
  }

$ogp = <<< EOM
<meta property="og:site_name" content="{$siteName}" />
<meta property="og:title" content="{$title}" />
<meta name="og:type" content="{$ogpType}">
<meta property="og:url" content="{$permalink}" />
<meta property="og:image" content="{$ogpImage}" />
<meta property="og:description" content="{$description}" />
<meta property="fb:app_id" content={$fbAppID} />
<meta name="twitter:card" content="{$cardType}" />
EOM;
  
  echo $ogp;
}

cf.

所管

なんとなくいい感じに OGP のメタタグを出力できるようになりました!
WordPress の全部を functions.php にマージして実行する仕組みにいまいち慣れない…


[参考]

おじP… ネタ切れ…

WordPress アップロードした画像を width, height 属性無しで取得したい

WordPress でアップロードした画像 (thumbnail) を img タグで取得する the_post_thumbnail() には自動的に width, height 属性がついてくるので場合によっては使いづらいときがあります。

1. post_thumbnail_html フィルターで the_post_thumbnail の出力内容を置き換える

<?php // functions.php
add_filter( 'post_thumbnail_html', 'remove_thumbnail_dimensions');

function remove_thumbnail_dimensions( $html, $post_id, $post_image_id, $size, $att ) {
    $html = preg_replace( '/(width|height)=\"\d*\"\s/', "", $html );
    return $html;
}

cf. How do you remove hard coded thumbnail image dimensions? - WordPress Development Stack Exchange

常に width, height 属性が不要であれば filter を使うのが手っ取り早そうです

2. wp_get_attachment_image_src を使って画像の URL を取得する

img タグを自分で作ってしまうなら画像の URL が取得できれば問題がない

wp_get_attachment_image_src(
  int $attachment_id, string|int[] $size = 'thumbnail', bool $icon = false
): array|false

cf. wp_get_attachment_image_src() | Function | WordPress Developer Resources

サムネイルの attachment_idget_post_thumbnail_id(int|WP_Post $post = null): int|false で取得できる

<?php
$thumbnail = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), $size );
$thumbnail = $thumbnail[0] ?: 'placeholder.jpg';
$title = get_the_title( $post->ID );

echo '<img src="' . $thumbnail . '" alt="' . esc_attr($title) . '" />';

画像の URL を取得してしまえばタグは自由にできますね!

おわり
WordPress のこと本当に何も覚えてない…


[参考]

2030年:すべてが「加速」する世界に備えよ 面白かったです!

WordPress ContactForm7 select の先頭の空白 option のテキストを変更したい

6億年ぶりに WordPress 案件をやっています。
Contact Form 7 の select をカスタマイズするメモ。

include_blank で追加される空の項目のテキストを変更したい

Contact Form 7 でフォームを作る際に 空の項目をドロップダウンメニューの先頭に追加する。 (include_blank) オプションを選ぶと先頭に <option value="">---</option> が追加されます。この HTML は固定値でショートコードからテキストを変更することができそうにありません。

wpcf7_form_elements filter を使って Contact Form 7 が出力する DOM をカスタマイズできる

functions.phpwpcf7_form_elements というフィルターを追加します

<?php // functions.php
function my_wpcf7_form_elements($html) {
  $text = '選択してください';
  $html = str_replace('<option value="">---</option>', '<option class="placeholder" value="" disabled selected>' . $text . '</option>', $html);
  return $html;
}

add_filter('wpcf7_form_elements', 'my_wpcf7_form_elements');

wpcf7_form_elements フィルターに渡される引数はまるっと フォームパーツの DOM が入っているので、変更したい箇所を力技で replace しています。 変更後の option に disabledselected 属性を追加することで最初だけ選ばれているけど変更すると選べなくなるので placeholder 的な挙動にすることができます。

デフォルト状態 Contact Form 7 select 👇 選択後 Contact Form 7 select

いいかんじになりました!
おわり₍ ᐢ. ̫ .ᐢ ₎


[参考]

最後に Contact Form 関係の記事書いたの5年前じゃん…

selector WIXOSS 救いがなくてとても好き…