技術編:ブログシステムを6年ぶりに作り直しました
このブログのシステムを、全面的に作り直しました。いま読んでいるこのページは、数日前までとは中身がまるごと別物になっています。 最初にお断りしておくと、この話は二部構成です。今回は技術の話をします。何がどう変わったのかを、実際に動くデモを交えて紹介していきます。「そもそもなぜ、noteもある時代に自分でブログを作り続けるのか」という思想の話は、次回にとっておきます。

本ブログではサーバーサイドの一部で使用
.png)
このブログのシステムを、全面的に作り直しました。いま読んでいるこのページは、数日前までとは中身がまるごと別物になっています。 最初にお断りしておくと、この話は二部構成です。今回は技術の話をします。何がどう変わったのかを、実際に動くデモを交えて紹介していきます。「そもそもなぜ、noteもある時代に自分でブログを作り続けるのか」という思想の話は、次回にとっておきます。
JAMStackでもページビュー数を取得して表示したい! ということで実装しました。 技術要素はこちら Google Analytics Reporting API v4 google-api-php-client MicroCMS patch API Google Analyticsのデータを閲覧権限で取得してきてNuxtのビルド時にごそっとpatchイベントを介してMicroCMS上で確認できるような設計にしました。 最終的にこんな感じでpv数がmicroCMSで確認できます。 あとは通常のJAMStackと同じで取得したpv数を表示する流れです。 実装: まずPHPでGoogle Analytics Reporting APIの導通をします こちらのページを参考に簡単に作れました。 そのあと、今回は記事ページの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([' $analytics = new Google_Service_AnalyticsReporting($client); // データを取得する期間 $dateRange = new Google_Service_AnalyticsReporting_DateRange(); $dateRange->setStartDate('2020-09-01'); $dateRange->setEndDate('today'); // 取得するメトリクスの指定 // // 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(' { "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でも適当に週一くらいで走らせる設計に変更しようと思います。
URLを貼り付けたらOGP情報があればそれを引っ張ってきて貼り付けるような仕様に対応しました
はまったので忘備録 公式によると以下curlコマンドで画像アップができます。 curl -X POST " \ -u your_private_api_key: \ -F 'file=iVBORw0KGgoAAAAN' \ -F 'fileName=hoge.png' PHPで書き直すと以下のようになります $POST_DATA = array( 'file' => 'iVBORw0KGgoAAAAN', 'fileName' => "hoge.png", ); $curl=curl_init(" curl_setopt($curl,CURLOPT_POST, TRUE); curl_setopt($curl, CURLOPT_POSTFIELDS, $POST_DATA); curl_setopt($curl,CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($curl,CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($curl,CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($curl, CURLOPT_USERPWD, $imagekit_privatekey.":"); curl_setopt($curl,CURLOPT_COOKIEJAR, 'cookie'); curl_setopt($curl,CURLOPT_COOKIEFILE, 'tmp'); curl_setopt($curl,CURLOPT_FOLLOWLOCATION, TRUE); $output= curl_exec($curl);crulの-uコマンドになじみがなくてよくわからなかったのですがどうやらこれはbasic認証らしいです。 phpのcurlでbasic認証を通す場合はcurl_setopt($curl, CURLOPT_USERPWD, $imagekit_privatekey.":");のように記述します またこの記事同様デフォルトでランダム文字列が入ってしまうのですが、外す場合にはuseUniqueFileNameをfalseにする必要があります ただ、今回はmultipart/form-dataでの送信のため、http-build-queryなどを通さず、直接送信しているため $POST_DATA = array( 'file' => 'iVBORw0KGgoAAAAN', 'fileName' => "hoge.png", 'useUniqueFileName' => false );とすると、正しく動作しません。 正確には $POST_DATA = array( 'file' => 'iVBORw0KGgoAAAAN', 'fileName' => "hoge.png", 'useUniqueFileName' => 'false' );と文字列リテラルで渡す必要があります。 これで正しくアップロードできます