JAMStackでもページビュー数を取得して表示したい! ということで実装しました。
技術要素はこちら
Google Analyticsのデータを閲覧権限で取得してきてNuxtのビルド時にごそっとpatchイベントを介してMicroCMS上で確認できるような設計にしました。
最終的にこんな感じでpv数がmicroCMSで確認できます。
あとは通常のJAMStackと同じで取得したpv数を表示する流れです。
実装:
まずPHPでGoogle Analytics Reporting APIの導通をします
こちらのページを参考に簡単に作れました。
https://blog.apar.jp/web/11573/
そのあと、今回は記事ページのpv一覧がほしいので、このようにphpを記述しました
<?php
// Google API クライアントライブラリの読込み
require_once __DIR__ . '/google-api-php-client/vendor/autoload.php';
// 鍵ファイルのパス
$key_file_location = __DIR__ . '/service-account-credentials.json';
// ビューID
$view_id = 'view_id';
// 認証処理
$client = new Google_Client();
$client->setApplicationName('sample');
$client->setAuthConfig($key_file_location);
$client->setScopes(['https://www.googleapis.com/auth/analytics.readonly']);
$analytics = new Google_Service_AnalyticsReporting($client);
// データを取得する期間
$dateRange = new Google_Service_AnalyticsReporting_DateRange();
$dateRange->setStartDate('2020-09-01');
$dateRange->setEndDate('today');
// 取得するメトリクスの指定
// https://developers.google.com/analytics/devguides/reporting/core/dimsmets
// PV
$pageviews = new Google_Service_AnalyticsReporting_Metric();
$pageviews->setExpression('ga:pageviews');
//ディメンションをpathに設定
$dimention = new \Google_Service_AnalyticsReporting_Dimension();
$dimention->setName( 'ga:pagePath' );
//部分一致"post"でページ全体をフィルタリング
$filter = new \Google_Service_AnalyticsReporting_DimensionFilter();
$filter->setDimensionName( 'ga:pagePath' );
$filter->setOperator( 'PARTIAL' );
$filter->setExpressions( [ 'post' ] );
//フィルタを適用
$filters = new \Google_Service_AnalyticsReporting_DimensionFilterClause();
$filters->setFilters([$filter]);
// リクエストの作成
$request = new Google_Service_AnalyticsReporting_ReportRequest();
$request->setViewId($view_id);
$request->setDateRanges($dateRange);
$request->setMetrics(array($pageviews));
$request->setDimensions( [ $dimention ] );
$request->setDimensionFilterClauses( $filters );
// リクエスト実行
$body = new Google_Service_AnalyticsReporting_GetReportsRequest();
$body->setReportRequests(array($request));
$reports_obj = $analytics->reports->batchGet($body);
// オブジェクトを配列変数に変換
$reports_array = json_decode(json_encode($reports_obj), true);
//一旦整形する
$pageviewarray = $reports_array['reports'][0]['data'][rows];
$outputarray = [];
//クエリパラメータ付きのパスは同一PVとして加算する
for ($i = 0; $i < count($pageviewarray); $i++) {
$realpath = explode("?",$pageviewarray[$i]['dimensions'][0])[0];
if(substr($realpath, -1) != '/'){
$realpath = $realpath . "/";
}
if($outputarray[$realpath]['pageview'] == null){
$outputarray[$realpath]['pageview'] = intval($pageviewarray[$i]['metrics'][0]['values'][0]);
}else{
$outputarray[$realpath]['pageview'] += intval($pageviewarray[$i]['metrics'][0]['values'][0]);
}
}
//JSで扱いやすいようにフォーマット変更
$output = [];
for ($l = 0; $l < count($outputarray) - 1; $l++) {
if(substr(array_keys($outputarray)[$l],0,6) == "/post/"){
$obj = array('path'=>array_keys($outputarray)[$l],'id'=>rtrim(substr(array_keys($outputarray)[$l],6),'/'),'pageview'=>$outputarray[array_keys($outputarray)[$l]]['pageview']);
}
array_push($output,$obj);
}
echo json_encode($output);
するといい感じにAPIができました
あとはこいつをnuxt.config.jsでビルド時に記事ページにpatchします
let pvobj = await axios.get("getpageview.php");
for(let pv = 0;pv<pvobj.data.length;pv++){
try {
console.log("try : " + pvobj.data[pv].id);
await axios.patch('https://yourdomain.microcms.io/api/v1/post/'+pvobj.data[pv].id,{"pv":pvobj.data[pv].pageview},{headers: { "X-MICROCMS-API-KEY": "your_microcms_key","Content-Type":"application/json" }})
} catch (e) {
console.log('Error!!')
}
console.log("done");
}
これでmicroCMSにPV数が記録されます。
問題点:
ビルドプロセスにpatch処理を入れたことで、microCMS側で設定しているGithub ActionのRepository dispatchイベントが発火され続け、Github Actionsのワークフロー一覧が大変なことになりました。
POSTイベントで自動投稿する記事があったので、API入稿もCIを走らせていましたが、今後patchを動かしていくのであればCI動いては困るので、API入稿でのCI発火は止めました。
また、このプロセス追加によってビルド時間が1分→5分くらいに伸びました
そんなにリアルタイム性が求めらていないデータなので、今後Github Actionsの無料枠を逼迫するようであればPHPにそのままpatchの処理を移管してcronでも適当に週一くらいで走らせる設計に変更しようと思います。