例えばQiitaだとTwitterでツイートするときに,タイトルとユーザー名からなる画像が生成される.
これをWordPressでも自前でやりたい
結果
いい感じにできました(主観)
画像生成サーバーの作成
Go言語でクエリパラメーターにテキストを入れると画像を返してくれるサーバーを作成した.
https://str-to-img.kajindowsxp.com/?text=例えばこんな感じ
全体のコードはここ
https://github.com/kajikentaro/str-to-img
画像を生成するコードは以下(抜粋).
あとはhttpと組み合わせ,デプロイするだけ
package services
import (
"flag"
"image"
"image/color"
"log"
"os"
"github.com/disintegration/imaging"
"github.com/fogleman/gg"
"github.com/pkg/errors"
"golang.org/x/image/font"
"golang.org/x/image/font/opentype"
)
type GenImageService struct{}
func NewGenImageService() *GenImageService {
return &GenImageService{}
}
func (s *GenImageService) GenImage(text string) image.Image {
flag.Parse()
dc := gg.NewContext(1200, 630)
dc.SetColor(color.RGBA{255, 255, 255, 255})
dc.DrawRectangle(0, 0, float64(dc.Width()), float64(dc.Height()))
dc.Fill()
frame, err := gg.LoadImage("services/src/frame.png")
if err != nil {
panic(errors.Wrap(err, "load background image"))
}
frame = imaging.Fill(frame, dc.Width(), dc.Height(), imaging.Center, imaging.Lanczos)
dc.DrawImage(frame, 0, 0)
face, err := fetchPostScriptFontFace("services/font/NotoSansJP-Medium.otf")
if err != nil {
log.Fatalln(err)
}
dc.SetFontFace(face)
dc.SetColor(color.Black)
drawStringMultiLine(dc, []rune(text), 100.0)
return dc.Image()
}
// PostScript アウトラインのフォント読み込み
func fetchPostScriptFontFace(fontfile string) (font.Face, error) {
ftBinary, err := os.ReadFile(fontfile)
if err != nil {
return nil, err
}
ft, err := opentype.Parse(ftBinary)
if err != nil {
return nil, err
}
opt := opentype.FaceOptions{
Size: 80.0,
DPI: 72.0,
Hinting: font.HintingNone,
}
face, _ := opentype.NewFace(ft, &opt)
return face, nil
}
func drawStringMultiLine(dc *gg.Context, text []rune, margin float64) {
width := float64(dc.Width())
drewStrCnt := 0
drewHeight := 40.0
log.Println(string(text))
for i := 0; i < len(text); i++ {
candidateStr := text[drewStrCnt : i+1]
candidateWidth, h := dc.MeasureString(string(candidateStr))
if candidateWidth <= width-2*margin {
// まだ右に余白がある場合
continue
}
dc.DrawStringAnchored(string(text[drewStrCnt:i]), margin, drewHeight, 0, 1)
drewStrCnt = i
drewHeight += h
}
dc.DrawStringAnchored(string(text[drewStrCnt:]), margin, drewHeight, 0, 1)
}
テーマファイルを編集
管理画面にログインし,「外観」→「テーマファイルエディター」→「テーマのための関数(functions.php)」を順にクリック
以下の内容を追記する
//投稿・固定ページのSNSシェア画像の取得(シェア画像優先)
if ( !function_exists( 'get_singular_sns_share_image_url' ) ):
function get_singular_sns_share_image_url(){
//NO IMAGE画像で初期化
$sns_image_url = get_no_image_url();
//本文を取得
global $post;
$content = '';
if ( isset( $post->post_content ) ){
$content = $post->post_content;
}
//投稿にイメージがあるか調べるための正規表現
$searchPattern = '/<img.*?src=(["\'])(.+?)\1.*?>/i';
if ($singular_sns_image_url = get_singular_sns_image_url()) {
$sns_image_url = $singular_sns_image_url;
} else if (has_post_thumbnail()){//投稿にサムネイルがある場合の処理
$image_id = get_post_thumbnail_id();
$image = wp_get_attachment_image_src( $image_id, 'full');
$sns_image_url = $image[0];
} else {
$sns_image_url = 'https://str-to-img.kajindowsxp.com?text='.urlencode(get_the_title());
}
return apply_filters('get_singular_sns_share_image_url', $sns_image_url);
}
endif;
解説
そもそもCocoonには「親テーマ(cocoon-master)」と「子テーマ(cocoon-child)」が存在し,インストール時には親ファイルをインストールした上で,子テーマを有効化していた.
ソースを見ると wp-content/themes/cocoon-master/tmp/header-ogp.php
の get_singular_sns_share_image_url()
を読んでいる
if (is_singular()){//単一記事ページの場合
if ($ogp_image = get_singular_sns_share_image_url()) {
echo '<meta property="og:image" content="'.esc_url($ogp_image).'">';echo "\n";
}
} else {//単一記事ページページ以外の場合(アーカイブページやホームなど)
if (is_category() && !is_paged() && $eye_catch = get_the_category_eye_catch_url(get_query_var('cat'))) {
$ogp_image = $eye_catch;
} elseif (is_tag() && !is_paged() && $eye_catch = get_the_tag_eye_catch_url(get_queried_object_id())) {
$ogp_image = $eye_catch;
} elseif ( get_ogp_home_image_url() ) {
$ogp_image = get_ogp_home_image_url();
} else {
if ( get_the_site_logo_url() ){//ヘッダーロゴがある場合はロゴを使用
$ogp_image = get_the_site_logo_url();
}
}
if ( !empty($ogp_image) ) {//使えそうな$ogp_imageがある場合
echo '<meta property="og:image" content="'.esc_url($ogp_image).'">';echo "\n";
}
wp-content/themes/cocoon-master/lib/utils.php
に get_singular_sns_share_image_url()
が定義されている.
//投稿・固定ページのSNSシェア画像の取得(シェア画像優先)
if ( !function_exists( 'get_singular_sns_share_image_url' ) ):
function get_singular_sns_share_image_url(){
//NO IMAGE画像で初期化
$sns_image_url = get_no_image_url();
//本文を取得
global $post;
$content = '';
if ( isset( $post->post_content ) ){
$content = $post->post_content;
}
//投稿にイメージがあるか調べるための正規表現
$searchPattern = '/<img.*?src=(["\'])(.+?)\1.*?>/i';
if ($singular_sns_image_url = get_singular_sns_image_url()) {
$sns_image_url = $singular_sns_image_url;
} else if (has_post_thumbnail()){//投稿にサムネイルがある場合の処理
$image_id = get_post_thumbnail_id();
$image = wp_get_attachment_image_src( $image_id, 'full');
$sns_image_url = $image[0];
} else if ( preg_match( $searchPattern, $content, $image ) && !is_archive() && is_auto_post_thumbnail_enable()) {//投稿にアイキャッチは無いが画像がある場合の処理
$sns_image_url = $image[2];
} else if ( $no_image_url = get_no_image_url() ){//NO IMAGEが設定されている場合
$sns_image_url = $no_image_url;
} else if ( $ogp_home_image_url = get_ogp_home_image_url() ){//ホームイメージが設定されている場合
$sns_image_url = $ogp_home_image_url;
} else {
$sns_image_url = NO_IMAGE_LARGE;
}
return apply_filters('get_singular_sns_share_image_url', $sns_image_url);
}
endif;
今回は「投稿にサムネイルがある場合」を除き,画像生成サーバーで作成した画像をOGPに設定するので先程のコードに修正した.
このutils.php
よりもfunctions.php
の方が先に読み込まれるので,functions.php
の関数が優先される形になる.