いま話題のスペースに出会えるspaces.bz(クローズ済み)では、デイリーランキングで動的OGPを実装しています。
実はこれ、Google SpreadsheetとGoogle Slidesを使って、GASで毎日OGP画像を生成して表示させているんです。 結構面白いアイデアなのでシェアします😊。
全体像
まずこの記事で紹介する全体像を示します。
- 動的OGPのもとになるSlidesを作成
- 動的OGPのデータのもとになるSpreadsheetを作成
- GASを作成
- SpreadsheetのデータをもとにSlidesの文字列を置換
- Slidesを画像ファイルでエクスポートしてDriveに保存
- Driveに保存した画像ファイルのIDをSpreadsheetに追加
- Slidesを元の文字列に置換し直す
- SpreadsheetをWebApp(API)で公開
- Nuxtアプリで動的OGPを設定
ちょっと長いですが、お付き合いいただけると嬉しいです🙏。
1. 動的OGPの元になるSlidesを準備
まずはいい感じのOGPのデザインをGoogle Slidesで作ります。
Coolです。ポイントとしてはOGPは1200mmx628mmのサイズがよいので、「ファイル > ページ設定」からスライドの縦横サイズを変更してます。
このスライドに書いている「name」はこの後置換するためのキーワードになってます。
2. 動的OGPのデータのもとになるSpreadsheetを準備
「name」を置換していきたいので、そんな感じのSpreadsheetを用意します。 spaces.bzの場合は、その日のランキング10位までをGASで集計して、そのデータを元に置換しています。 今回は簡単な例なので、次のようなシートを用意します。
id | name | ogpId |
---|---|---|
1 | Test A | |
2 | Test B | |
3 | Test C |
ogp_id
はいまのところ空ですが列だけ用意しておきます。後でGASでOGP画像のファイルを生成したときに画像ファイルのIDをセットするカラムです。
3. GASを作成
この記事の佳境です。
まずコードの全容をさらします。 説明しやすいように書いていますが、内容を理解いただければ色々な書き方があります。
少し長いですが、少しずつ区切ってみていきます。
3-1. 各種変数の設定
最初のconst
たちは変数の設定です。
変数 | 説明 |
---|---|
ss | 2で作成したSpreadsheet。<SpreadsheetのID> はhttps://docs.google.com/spreadsheets/d/<この部分>/edit |
sheet | 2で作成したシート |
data | sheet のデータをArrayで取得したもの |
columnNames | data の1行目を取り出したもの |
presentationId | 1で作成したSlidesのID。https://docs.google.com/presentation/d/<この部分>/edit#slide=id.p |
folder | 作成したOGP画像を格納しておきたいGoogle Driveのフォルダ。<FolderのID> はhttps://drive.google.com/drive/u/0/folders/<この部分> 。このフォルダは公開設定にしておきます(後述) |
このとき、data
とcolumnNames
は次のようになっています。
3-2. 置換して画像保存して置換し直す
ここが核です。なにか色々やっているようですが、ほとんどの行は別に作成した関数を呼び出しているのでそこも説明していきます。
まず、全体はdata.forEach
で回しています。 最初にrow[1]
で、Test A
, Test B
, Test C
をname
に格納しています。 それに続いて、次の処理を行います。
- スライドのテキストを
name
に置換(replaceText()
) - スライドをイメージ保存(
downloadImage()
) - 保存したファイルのIDを
data
に追加(row[2] = ogpId
) - スライドのテキストを置換し直す(
resetText()
)
3-2-1. スライドのテキストを置換
スライドのテキストの置換処理を行うreplaceText()
関数を定義しました。
引数はpresentationId
と、置換後の文字列name
です。 まず、SlidesApp.openById(presentationId)
で置換したいスライドがあるSlidesを開きます。 そして、getSlides()[0]
を使って、そのSlidesの1枚目のスライドを取得します。 そのslide
に対してreplaceAllText()
を実行することで、slide
の中の'name'
の文字列を引数のname
に置換しています。 最後にpresentation.saveAndClose()
で置換を確定しています。saveAndClose()
を行わないと、次のイメージ保存で置換前の状態で保存されてしまうので要チェックです。
置換の処理はこれだけです。 置換したい文字列が複数ある場合でも同じやり方でslide.replaceAllText()
を追加すればできます。 複数のスライドに対してはpresentation
に対してreplaceAllText()
したり、getSlides()
の結果をforEach
で回してスライド1枚ずつに処理することで実現できます。
3-2-2. スライドを保存
これで動的OGPのイメージの準備ができたので、これをイメージファイルに保存します。今回はpng
で。
何をするかというと、SlidesをダウンロードするURLにリクエストを投げて、レスポンスをpngファイルにして保存しようというやり方です。
引数は、presentationId
とfolder
、そしてファイル名としてfileName
を取ります。 最初のpresentation
とslide
の式はreplaceText()
と同じなので説明は省略します。 slideId
はそのスライドのIDで、https://docs.google.com/presentation/d/<presentationId>/edit#slide=id.<'この部分'>
です。 これはslide.getObjectId()
で取得ができます。
これらの変数を使ってリクエストURLurl
を作ります。 リクエストには認証が必要なので、ScriptApp.getOAuthToken()
を使ってBearer認証できるようにoptions
を作っておきます。
このurl
とoptions
を使って、UrlFetchApp.fetch()
でリクエストを投げ、レスポンスをresponse
に格納しています。 response
はHTTPResponse
Classなので、画像ファイルとして扱うためにgetAs(MimeType.PNG)
でpngファイルに変換し、setName()
でファイル名を設定します。 それを、folder.createFile()
でfolder
にファイルとして保存しているって流れです。 最後に、保存したファイルfile
のIDをgetId()
で取得して、返り値にしています。
3-2-3. 保存したファイルのIDをデータに追加
先程説明したようにdownloadImage()
は作成したpngファイルのIDをreturnしてます。 それをrow[2]
、つまりogpId
のカラムに設定しています。 詳しくは後ほど紹介しますが、これがNuxtアプリでGoogle Driveの画像ファイルをOGPに設定する肝だったりします。
3-2-4. スライドのテキストを置換し直す
ここまで終わったら次のループのためにスライドの文字列を元の'name'
に戻しておきます。このためにresetText()
の関数を用意して呼び出しています。
やっていることはreplaceText()
の逆なので説明は省略します。
3-3. スプレッドシートのogpIdを更新
最後にSpreadsheetのogpIdカラムを更新しましょう。 すでにここまでの処理でdata
の各Array要素の3つ目の要素にogpId
が格納されているので、Spreadsheetを上書きすればOKですね。
ということで、data.unshift(columnNames)
でdata
の1つ目の要素に列の名前を戻して、 sheet.getRange().setValues()
でデータを上書きしています。
ここまでで画像を作成するステップが完了です。😊 ここからはSpreadsheetをもとにNuxtアプリでOGP画像を動的に設定してみましょう。
4. SpreadsheetをWebApp(API)で公開
次は先程OGPのIDを追記したSpreadsheetをWebAppで公開していきます。 このやり方は、以前に記事を書いたので詳細はそちらを見てください。
GASのコードは次のようになります。先程のコード.js
に追記していきましょう。
これを、デプロイしてWebApp公開しましょー。
5. Nuxtアプリで動的OGPを設定
まずは、Nuxtアプリで先程公開したWebAppにリクエストする下準備をします。今回はaxios
を使うことを前提として、serverMiddleware
経由でWebAppを呼び出します。 こちらも過去に記事を書いていますので、詳細についてはそちらを参照してください。
次の更新、もしくは新規作成します。
これで下準備が完了です。あとはpages
のファイルでasyncData()
を使い情報取得して、head()
で画像のパスを指定してあげるだけです。
今回はpages/index.vue
でクエリパラメーターid
に応じてOGP画像を出し入れしましょう。パスパラメーターとかでもやり方は基本的に変わりないです。
例えばこんな感じです(nuxt.config.js
で他のタグは設定されている前提です)。 asyncData
でクエリパラメーターid
が存在する場合は、users
から同じid
のuser
を探してます。 見つかったらogpUrl
にhttps://drive.google.com/uc?export=view&id=${user.ogpId}
を設定します。 存在しない場合は<共通のOGPイメージのパス>をセットし、head()
でog:image
のproperty
としてogpUrl
を設定しています。 こうすることでクエリパラメーターid
に応じて動的にOGPを設定できます。
さて、ここで出てきたhttps://drive.google.com/uc?export=view&id=
です。 Google Drive上で画像ファイルを見ようとするとプレビューモードで表示されるでしょう。この状態ではコードからすれば画像ファイルとして扱うことができません。 実はhttps://drive.google.com/uc?export=view&id=<表示したい画像ファイルのID>
であれば、プレビューモードではなく画像ファイルとして認識させることができます。 また、これで表示できるのは閲覧権限をもつユーザーのみですので、OGP画像を保存しているフォルダはすべてのユーザーに閲覧権限で公開されている必要があります。
ngrok で公開し、 Twitter Card Validator でOGPが正しく設定されているか確認してみましょう。
id=1のとき
id=2のとき
動的にOGP画像が表示されてることを確認できました。
まとめ
長くなってしまいましたが、これでSpreadsheetとSlidesを使ってOGP画像を生成しNuxtアプリで動的OGPを実現する一連の流れを紹介させていただきました。 かなり色々なサイトを参考にさせていただいてここまでできたので、この場を借りてお礼を。m(__)m GAS、かなり色々なことができるので楽しいですね。
参考
- Slides Service | Apps Script | Google for Developers
- Spreadsheet Service | Apps Script | Google for Developers
- Drive Service | Apps Script | Google for Developers
- [Google Apps Script]Googleスライドのプレゼンテーションを他形式に変換する | 初心者備忘録
- Google ドライブでファイル名とリンクの一覧をお手軽に取得する方法 | DevelopersIO
- Google Drive に保存した画像を直接呼び出せるURLの取得 #GoogleDrive - Qiita