WordPressは使いやすく自由度が高い反面、自分で設定しないといけないことが一定数存在します。その代表がOGPの設定ともいえるでしょう。プラグインでの実装というのもありだと思いますが、プラグインは入れすぎだと重くなる、ある意味で自由が利かないという問題があります。
OGPの設定自体は簡単ですが、見栄えを気にしだすと気になるのがOGPに使う画像(og:imageの部分)です。このテーマや記事を書く側の都合でアイキャッチ画像を設定しないことが大半だったりするので、OGPに対応しても固定的な画像しか出せないというのが欠点になりやすいです。
そこで、タイトルにある通り、WordPressでプラグインを使わないでOGPの設定をしつつ、画像を自動生成する方向で作業をしてみました。
OGPの設定は調べてみるとWordPressのテーマエディターでできる程度には簡単なようです。調べればいくらでも出てきますが、例えばこのような記事が出てきます。
https://296.co.jp/article/19031520191205900
1から書いても良かったのですが、楽に越したことはないので今回はここを参考にしました。
書いてあるコードをコピペし初期設定をするだけで中身はさておきOGPの設定はできます。これだけでも十分見た目は立派なものができます。この例がこんな感じです。
この画像を見て思うのが、記事の概要が横に書かれているものの、左の写真はただの飾りになってしまい、情報が一切ないという点ですね。
Twitterの場合は、summaryとsummary_large_imageのどちらのタグかによって表示が変わりますが、どちらの場合も同じ状態です。オシャレなサイトだと海辺の綺麗な写真とかそんなのを設定している人が多いように思いますが、情報は一切入ってこないという点だけは変わりません。
これをなんとかしたいなーと思うと、ページごとに表示する画像を変えるという作業が必要になります。これを手動でやろうと思うと、記事ごとに画像を用意して、それを設定してと面倒が増えていきます。しかも、ストレージを圧迫したり、ページに画像が増えるので僅かですが速度の低下を招くという点もいただけませんね。
こういったことを考慮すると、文字をいれれば良いのではと考えます。文字をいれるとなるとヘッドレスブラウザとかcanvas APIあたり使うのかな、という考えは間違っていないようで、調べてみると同じような考えの方が多いですね。サーバーサイドにかなり余裕があるならそれでも良いかなと思ったりもするのですが、偏見としてヘッドレスブラウザやらcanvasは重いイメージがあります。
他の方法はないかと探していると、求めていたことをやっている記事を発見しました。
https://qiita.com/kiiiiihara/items/9b5c9b1d9f55bdf1cd98
OGPの画像を自動で作るということをやっている人の記事です。細かいことは書いていませんが、ひとまず実装してみます。この人の実装では分の整形が無かったので、その部分を追加で実装しました。文の整形は参考になりそうなコードが多かったので合いそうなものを拝借しています。
あとはこれだけだとまだ不足しているのがセンタリングのコードが欠けているようなので、適当に実装しました。数ピクセルならずれても気にならないだろうという適当さが滲み出ています。
で、出来上がったコードがこれです。適当に切り貼りしすぎたのとセンタリングの部分が少しごちゃごちゃしたので変数が悲惨なことになっていますが、ご愛敬ということで…
<?php
$fontSize = 56; // 文字サイズ
$fontFamily = 'font.ttf'; // TrueTypeフォントを指定する
$MarginX=50;//横方向マージン
$MarginY=50;//縦方向マージン
$angle=0;//文字を回転させる場合用
$txtX = $fontSize+$MarginX; // 文字の横位置(文字の左が基準)
$txtY = $fontSize * 2+$MarginY; // 文字の縦位置(文字のベースラインが基準)
$txt = $_GET['text']; // テキスト拾う用
$Nx=1200; //元画像の横ピクセル数
$Ny=630; //元画像の縦ピクセル数
$ENx=$Nx-$txtX*2;//有効横ピクセル数
$ENy=$Ny-$txtY*2;//有効縦ピクセル数
$newtxt=imageWordwrap($fontSize, $angle, $fontFamily, $txt, $ENx);
$initpos=imagettfbbox($fontSize, $angle,$fontFamily,$newtxt);
$BoxHight=$initpos[1]-$initpos[7];
$txtln=round($BoxHight/$fontSize);
$step=$fontSize/2;
$centY=$Ny/2+$MarginY;
$initcol=$centY+$fontsize*2;
$img = imagecreatefrompng('base.png'); // テキストを載せる画像
$color = imagecolorallocate($img, 0, 0, 0); // テキストの色指定(RGB)
imagettftext($img, $fontSize, $angle, $txtX,$initcol-$txtln*$step, $color, $fontFamily, $newtxt);//初期位置から行分だけシフト
//imagestring($img, 5, $txtX , $txtY, $txt, $white);
header('Content-Type: image/png');
imagepng($img);
imagedestroy($img);
/**
* 画像の幅で折り返し
* @param int $size 文字サイズ
* @param int $angle 角度
* @param string $font フォントファイルへのパス
* @param string $text 高さと幅を知りたい文字列
* @param int $imageWidth 画像の幅
* @param string $break 改行文字
* @return string
*/
function imageWordwrap(
int $size,
int $angle,
string $font,
string $text,
int $imageWidth,
string $break = "\r\n"
): string {
/** @var string[] $cahrs 1文字ずつに分解。絵文字非対応。対応するライブラリとフォントを見つける必要あり */
$chars = mb_str_split($text);
$lines = [];
$currentLine = '';
foreach ($chars as $ch) {
$wh = getTextSize($size, $angle, $font, $currentLine.$ch);
if ($wh['width'] > $imageWidth) {
$lines[] = $currentLine;
$currentLine = $ch;
} else {
$currentLine .= $ch;
}
}
$lines[] = $currentLine;
return implode($break, $lines);
}
?>
imagestringは日本語では使えないのとエイリアシングが効いていなかったりと不自由なので使っていないのですが、デバッグの都合で使っていました。最初は画像だけしか出てこなかったので原因を探ったところフォントの指定がおかしかったのが原因だったというオチです。もし画像だけ表示されているようなら一度コメントアウトを外してみて動作確認をすると原因が切り分けれると思います。どこかの参考ページに書いていますが、実装の都合でデバッグが怠いので総当たりでやるのが最短というパターンです。
ファイル構成としては参考にしたページと同じ構成でフォントファイルを基となる画像を同じディレクトリに放り込んでいます。ローカルパスでファイルを指定しているだけなのでそこらへんは好きに構成したら良いかと。
簡単にこのコードが何をしいるのかを書いておくとまず下の画像を読み込みます。
この画像に文字をのせているという形ですが、この枠内に収まるように改行するように、長い文を改行してくれるimageWordwrap関数を定義してそれを使っています。
後は改行された文字列をのせるだけ…ではなく、大きさに応じて縦方向のセンタリングを行っています。横方向はただ面倒だったので辞めました(そんな短いタイトル使わないし)。
使い方も書いてある通り、URLにtext値を放り込むだけで画像が変わってくれます。例えばこのようにしたとしましょう。
ogpimg.php?text=アメンボ赤いなあいうえお
これを表示するとこんな感じ。
文字数を変えても上手く改行されますし、センタリングもできますし、フォントサイズを変えても上手く動くので満足です。
あとはこいつをog:imageに使ったら目的通り、OGPの設定をしつつ画像の自動生成ができます。phpの部分はフルパスで記述しておきます。
content="https://example.com/ogpimg.php?text='.esc_attr($ogp_ttl).'"
これをOGPに使うようにするとこんな感じです。
これで共有したときの見栄えが良くなりました(共有するとは言っていない)。