WordPressでアナリティクスから前日のPVを取得して、オススメ記事を作る方法(APIは1日1回だけ)

シェアする:

この記事をおすすめしたい人

  • WordPressでアナリティクスからPVを取得したい人
  • WordPressでアナリティクスのPV降順でオススメ記事を作りたい人
  • つまりオレ

今回は前日のPVでソートしたオススメ記事5件みたいなのを作る第2弾です。

前回、カスタムフィールドのみ利用する方法を考えて、あれで求めているものは達成。 構造的にもシンプルでけっこう気に入っているんですが、せっかくなので今回はGoogleアナリティクスからしっかりとしたPVを拾ってくる方法を模索します。

今回の開発コンセプトは次の通りです。

  • WordPress上で前日のPVを取得する
  • Reporting APIを利用して、GoogleアナリティクスからPVを取得
  • データベースを直接使わない
  • APIを叩くのは1日1回だけ

要はReporting APIを使う以外はWordPressの機能だけで完結させようってことです。

アナリティクス Reporting APIを有効にする

まずはGoogle API ConsoleでReporting APIを有効にする必要があります。

今回はReporting APIの導入がメインではないので、手順については公式のガイドを参考にしてください。

有効にすると認証鍵がファイルで手に入りますが、このファイル名は「client_secrets.json」で、WordPressのテーマフォルダに置かれているものとして話を進めます。

Reporting APIのクライアントライブラリをインストール

今回はWordPress上で作業を行うので、PHP用のReporting APIのライブラリをインストールします。

PHPのパッケージ管理ツール「Composer」を利用してこの↓ようにインストールするか、


composer require google/apiclient:^2.0

公式のGitHubからダウンロードしてインストールします。

インストール場所は使用しているWordPressのテーマフォルダの中が良さそうです。

以下、テーマフォルダ内の「vender」フォルダにライブラリがインストールされているものとします。

Reporting APIをとりあえず動かしてみる

先に断っておきますが、

アナリティクスへの理解が深くないと意味不明な言葉がけっこうでてきます。

そのせいで何が何やらワケワカメでした。

なので僕と同程度の知識の人でも何をやっているのか理解しやすいように書く努力をします。

アナリティクスのデータを取得するまでの流れ

公式のガイドを見るとけっこう複雑なコードが書かれています。

ですがなくてもいいものも含まれているようで、流れを理解しやすいように削りまくったコードはこの↓ようになりました。


//ライブラリを読み込み
require_once __DIR__ . '/vendor/autoload.php';

//認証用のクラス
$client = new Google_Client();

//認証したクラスを利用してアナリティクス用のクラス
$analytics = new Google_Service_AnalyticsReporting($client);

//取得するデータのオプションを設定するクラス
$request = new Google_Service_AnalyticsReporting_ReportRequest();

//データを取得するためのクラス
$body = new Google_Service_AnalyticsReporting_GetReportsRequest();

//実際にデータを取得
$response = $analytics->reports->batchGet( $body );

言葉にするとこんな↓イメージ。

  1. 認証してー
  2. アナリティクス用のクラス作ってー
  3. どういうデータを要求するか決めてー
  4. データ取得の準備してー
  5. いざデータ取得!

以下、各パートの詳細を見ていきます。

Google_Clientクラスで認証

認証部分のコード↓です。


$client = new Google_Client();
$client->setAuthConfig(__DIR__ . '/client_secrets.json');
$client->addScope(Google_Service_Analytics::ANALYTICS_READONLY);

setAuthConfig()の引数が、Google API Consoleからダウンロードしてきた認証鍵のパスなので、変更している場合は調整してください。

それ以外はこのままコピペでOK。 変更する場所はなさそうです。

アナリティクス用のクラスを作成

ここは特にすることはありません。


$analytics = new Google_Service_AnalyticsReporting($client);

取得するデータのオプションを設定

最も難解で、最も重要な部分です。

Google_Service_AnalyticsReporting_ReportRequest()クラスを利用して、どのようなデータが欲しいのかを定義します。

最低限必要なのは、次の3点。

  • アナリティクスのビューID
  • いつからいつまでのデータが必要なのか
  • メトリック

メトリック????

メトリックというのは「ページビュー数が欲しい!」「ユーザー数が欲しい!」とかそういうのみたいです。

ページビューの場合はこの↓ように書きます。


$metric = new Google_Service_AnalyticsReporting_Metric();
$metric->setExpression("ga:pageviews");

日付の指定は、前日のPVが欲しいのでこの↓ように。


$dateRange = new Google_Service_AnalyticsReporting_DateRange();
$dateRange->setStartDate("yesterday");
$dateRange->setEndDate("yesterday");

データを取得する日を開始と終了の2点決めます。

基本は「YYYY-MM-DD」で指定し、その他に「today」「yesterday」「7daysAgo」のような文字列も使えるそうです。

アナリティクスのビューIDはアナリティクスを開いて「管理」「ビューの設定」にある「ビューID」です。 以下、「VIEW_ID」で定数定義されているものとします。

これらを合わせると設定部分のコードはこの↓ようになります。


$dateRange = new Google_Service_AnalyticsReporting_DateRange();
$dateRange->setStartDate("yesterday");
$dateRange->setEndDate("yesterday");

$metric = new Google_Service_AnalyticsReporting_Metric();
$metric->setExpression("ga:pageviews");

$request = new Google_Service_AnalyticsReporting_ReportRequest();
$request->setViewId(VIEW_ID);
$request->setDateRanges($dateRange);
$request->setMetrics(array($metric));

この設定だと、サイト全体の前日の総PVを取得してきます。

ここはけっこう難しいので、後で僕が実際に使ったその他のオプションも紹介してみます。

データを取得するためのクラス

ここは簡単です。


$body = new Google_Service_AnalyticsReporting_GetReportsRequest();
$body->setReportRequests( array( $request) );

データを取得するためのクラスに先ほどの設定したオプションをセットするだけ。

実際にデータを取得する部分

ここもこれまでの成果からbatchGet()関数でデータを取得するだけ。


$response = $analytics->reports->batchGet( $body );

ここまでのコードをまとめるとこう↓なります。


//アナリティクスのビューID
define("VIEW_ID", "XXXXXXXXX");

//ライブラリを読み込み
require_once __DIR__ . '/vendor/autoload.php';

//認証用のクラス
$client = new Google_Client();
$client->setAuthConfig(__DIR__ . '/client_secrets.json');
$client->addScope(Google_Service_Analytics::ANALYTICS_READONLY);

//アナリティクス用のクラス
$analytics = new Google_Service_AnalyticsReporting($client);

//取得する日付の範囲を設定
$dateRange = new Google_Service_AnalyticsReporting_DateRange();
$dateRange->setStartDate("yesterday");
$dateRange->setEndDate("yesterday");

//取得するデータの種類を設定
$metric = new Google_Service_AnalyticsReporting_Metric();
$metric->setExpression("ga:pageviews");

//上記設定をまとめる
$request = new Google_Service_AnalyticsReporting_ReportRequest();
$request->setViewId(VIEW_ID);
$request->setDateRanges($dateRange);
$request->setMetrics(array($metric));

//データを取得する準備
$body = new Google_Service_AnalyticsReporting_GetReportsRequest();
$body->setReportRequests( array( $request) );

//実際にデータを取得
$response = $analytics->reports->batchGet( $body );

赤字のビューIDの部分は自分のものに変更してください。

この状態でコピペで動かしてみて、ちゃんと$responseに値が返ってくればここまで成功です。

APIが返すデータの中身

APIが返すJSONをシンプルに書くとこの↓ような形になっています。


{
  "queryCost": null,
  "reports": [
    (レポートの中身)
  ]
}

メインの戻り値である「reports」は配列になっていて、この↓部分で複数の$requestを指定した場合に対応しています。


$body->setReportRequests( array( $request) );

今回はひとつしかリクエストしていないので「reports」の最初の要素を見てみるとこんな↓感じ。


{
  "nextPageToken": null,
  "columnHeader": {
    …
  },
  "data": {
    …
  }
}

欲しいのは「data」の中身で、こんな↓感じ。


{
  "dataLastRefreshed": null,
  "isDataGolden": null,
  "rowCount": 1,
  "samplesReadCounts": null,
  "samplingSpaceSizes": null,
  "rows": [
    …
  ],
  "totals": [
    …
  ],
  "minimums": [
    …
  ],
  "maximums": [
    …
  ]
}

さらに「rows」の中身↓。


[
  {
    "dimensions": null,
    "metrics": [
      {
        "values": [
          "9999"
        ]
      }
    ]
  }
]

「rows」も配列ですが、今回リクエストしたのが「サイト全体の前日の総PV」と単一の値なので要素がひとつしかありません。 実際の作業ではここはループを回すことになります。

この「rows」を取り出すにはこの↓ように。


$rows = $response[0]->getData()->getRows();

前日の各ページのPVを取得

Reporting APIでデータを取得する流れ、返ってきたデータの形がなんとなく分かりました。

あとはReportRequestのオプションをもうちょっと細かく指定してやるだけです。

ディメンションでパス(URL)を指定

ディメンション????

公式の説明を見ると「ディメンションはデータの属性です」とあります。 「たとえば、ディメンション ga:city はセッションの性質を示し、横浜、川崎などセッションが発生した市区町村を示します」とも。

まぁ、全く意味が分からないわけですが。

挙動だけ見てみると、「指定した要素でメトリックを分割」みたいな感じでしょうか。

メトリックにPV、ディメンションにパス(URL)を指定すると、各URL(ページ)ごとのPV数を取得してくれます。

書き方はこの↓ような感じ。


$dimention = new Google_Service_AnalyticsReporting_Dimension();
$dimention->setName("ga:pagePath");

$requestへのセットはこう↓。


$request->setDimensions(array($dimention));

「rows」の中身はこの↓ようになります。


{
  "dimensions": [
    "/post/begginer/"
  ],
  "metrics": [
    {
      "values": [
        "10"
      ]
    }
  ]
},

先ほどはnullだった「dimensions」に、トップページからの相対パスが入ります。 「metrics」内の「values」がPV数です。

これで各ページのPVを取得できたので後はPHP側でも処理できますが、もうちょっとAPI側で使いやすい形にしてみましょう。

ディメンションフィルタで不要なページを除外

人気記事を作る上で「トップページ」「一覧ページ」「カテゴリページ」など、不要なページがあります。 APIのレスポンスを軽量化するためにこれらを除外してみましょう。

ホワイトリスト形式で除外

このサイトの投稿記事URLはこの↓ようになっています。
/post/XXXXXXXXX/

このようにURLから欲しいページを絞り込める場合はホワイトリスト形式でフィルタをかけることができます。

このサイトの投稿記事だけ取得したい場合だと、コードはこの↓ようになります。


$filter = new Google_Service_AnalyticsReporting_DimensionFilter();
$filter->setDimensionName("ga:pagePath");
$filter->setOperator("BEGINS_WITH");
$filter->setExpressions( ["/post/"] );

「setDimensionName」でどの項目でフィルタをかけるかを指定します。 「ga:pagePath」だとURLでフィルタをかけます。

「setOperator」は次に指定する「Expression」でディメンションをどう評価するかを決めます。 「BEGINS_WITH」は「指定した値で始まる」です。 この演算子はけっこうな種類があるので公式を見てみてください。 正規表現も使えます。

「setExpressions」は評価に使う値です。

以上からこのフィルタは「/post/で始まるパスのページのみ取得」となります。

ブラックリスト形式で除外

カテゴリページやタグページを除外する場合はブラックリスト形式でフィルタをかけます。

「/cat/」で始まるパスを除外するコードはこう↓なります。


$filter = new Google_Service_AnalyticsReporting_DimensionFilter();
$filter->setDimensionName("ga:pagePath");
$filter->setNot(true);
$filter->setOperator("BEGINS_WITH");
$filter->setExpressions( ["/cat/"] );

先ほどとほぼ同じコードですが赤字の行が追加されています。

「setNot」で「true」を指定すると、マッチしたページを除外するようになります。 デフォルトは「false」なのでホワイトリスト形式の場合は設定不要です。

フィルタを追加するコード

ディメンションを追加する場合は直接$requestにセットしましたが、ディメンションフィルタを追加する際にはもうひと手間必要です。

コードはこの↓ようになります。


$clause = new Google_Service_AnalyticsReporting_DimensionFilterClause();
$clause->setFilters(array($filter));

DimensionFilterClauseなるクラスに先にセットする必要があります。

その後に$requestにセット↓します。


$request->setDimensionFilterClauses($clause);

なんでこのようなしちめんどくさいことになっているかというと、setFiltersの引数が配列になっているんですね。 つまり複数のフィルタをセットできます。

その場合、複数のフィルタを「AND」で評価するのか「OR」で評価するのかを設定するレベルが必要だったからなんじゃないかと考えています。 デフォルトでは「OR」で評価されるようです。

複数のフィルタを追加する方法

カテゴリページもタグページも除外したい場合などは、複数のフィルタをかけます。


$filter1 = new Google_Service_AnalyticsReporting_DimensionFilter();
$filter1->setDimensionName("ga:pagePath");
$filter1->setNot(true);
$filter1->setOperator("BEGINS_WITH");
$filter1->setExpressions( ["/cat/"] );

$filter2 = new Google_Service_AnalyticsReporting_DimensionFilter();
$filter2->setDimensionName("ga:pagePath");
$filter2->setNot(true);
$filter2->setOperator("BEGINS_WITH");
$filter2->setExpressions( ["/tag/"] );

$clause = new Google_Service_AnalyticsReporting_DimensionFilterClause();
$clause->setFilters(array($filter1, $filter2));
$clause->setOperator("OR");
$clause->setFilters(array($filter1, $filter2));

$request->setDimensionFilterClauses($clause);

$filter1でカテゴリページを除外、$filter2でタグページを除外して、2つのフィルタは「OR」で評価するよう指定しています。

各ページをPV降順で取得する方法

どうせ取得した後に並べ替えるので、それならもうAPI側で並べ替えておきます。


$orderby = new Google_Service_AnalyticsReporting_OrderBy();
$orderby->setFieldName("ga:pageviews");
$orderby->setSortOrder("DESCENDING");

「setFieldName」でソートするディメンションを指定、「setSortOrder」で降順/昇順を指定します。

もうひとつ「orderType」というのも指定できるんですが、PVの場合はデフォルト値で問題なくソートできているようでした。

$requestにセットはこう↓。


$request->setOrderBys($orderby);

取得件数を絞る方法はない…?

こういうAPIって「5件まで取得」みたいに上限を指定する方法があることが多いんですが、公式を見ているとなさそう?

Reporting APIのデータとWordPressの記事IDを関連づける

取得したデータは相対パスなので、これをWordPressの記事IDと紐付ける作業を行います。

以前調べた時はパーマリンクから記事IDを得る方法が見つからなくて、先に全記事をループで回してIDとパーマリンクのリストを作ってから紐付けていたんですが、今調べたらurl_to_postid()なる関数が見つかりました。

これを使えば楽勝ッスわ。

$responseにbatchGet()の戻り値が入っているものとして、コードはこう↓なりました。


$rows = $response[0]->getData()->getRows();

$data = array();

foreach ( $rows as $row ) {
  $path = $row["dimensions"][0];
  $pv = $row["metrics"][0]["values"][0];
  $url = home_url($path);
  $id = url_to_postid($url);
  
  $data[$id] = $pv;
}

配列の中身を確認せず決め打ちで何やらヒヤヒヤするコードですが、これで$dataにキーが記事ID、値はPVという配列が入りました。

あとはこれを日付更新後に一度だけ実行するようにすれば完成です。

アクションフックとカスタムフィールドでPV降順の記事を呼び出す

ここからCRONで時間トリガーの処理や、データベースに保存して、とやりだすとWordPressユーザにはランニングコストが大きいです。

なので、

ここから先はWordPressの機能だけでやります!

考え方は前回の記事と同様で、カスタムフィールドに今日の日付を入れておいて、wp_headが呼ばれた際に日付が現在日時と一致するかチェック。 一致しなければReporting APIからデータを取得してカスタムフィールドに放り込む。 一致すればカスタムフィールドからデータを取り出す、という方法です。

カスタムフィールドに配列入るのかなーと試してみたら普通に入ったのでこれが可能です。

コードはこの↓ような感じにしました。


date_default_timezone_set('Asia/Tokyo');

define("ORE_PV_LIST", "ore_pv_list");
define("ORE_PV_DATE", "ore_pv_date");
define("ORE_PV_VALUE", "ore_pv_value");

add_action('wp_head', function () {
  $home_id = get_option("page_on_front");
  
  $today = date("Ymd");
  $date = get_post_meta($home_id, ORE_PV_DATE, true);
  
  if ( strcmp($today, $date) != 0 ) {
    $data = get_pv_from_api();
    
    update_post_meta($home_id, ORE_PV_DATE, $today);
    update_post_meta($home_id, ORE_PV_LIST, $data);
    
    foreach ($data as $id => $pv) {
      update_post_meta($id, ORE_PV_VALUE, $pv);
    }
  }
});

get_pv_from_api()はこれまでにやってきたReporting APIから記事IDとPVの配列を作る関数です。

このデータをトップページ(フロントページ)のカスタムフィールドに保存しています。 トップページを設定していない場合は、常に特定可能なテキトーなページで大丈夫です。

前回と違い、ログインユーザだろうが固定ページだろうが、この関数は実行されます。 投稿ページに限定する必要がないので。

後は、オススメ記事を表示したい部分で、このコード↓でPV降順のリストを取得するだけです。


$query = array(
        'post_type' => 'post', 
        'post_status' => 'publish', 
        'posts_per_page' => 5,
        'orderby' => 'meta_value_num',
        'order' => 'DESC',
        'meta_key' => ORE_PV_VALUE,
);

$posts = new WP_Query($query);

コピペで使えそうなまとめ

まず、APIからデータを取得する関数↓をfunctions.phpに追加します。 赤字の部分は各自の環境に合わせてください。


//アナリティクスのビューID
define("VIEW_ID", "XXXXXXXXX");

//ライブラリを読み込み
require_once __DIR__ . '/vendor/autoload.php';

function get_pv_from_api() {
  //認証用のクラス
  $client = new Google_Client();
  $client->setAuthConfig(__DIR__ . '/client_secrets.json');
  $client->addScope(Google_Service_Analytics::ANALYTICS_READONLY);

  //アナリティクス用のクラス
  $analytics = new Google_Service_AnalyticsReporting($client);

  //取得する日付の範囲を設定
  $dateRange = new Google_Service_AnalyticsReporting_DateRange();
  $dateRange->setStartDate("yesterday");
  $dateRange->setEndDate("yesterday");

  //取得するデータの種類を設定
  $metric = new Google_Service_AnalyticsReporting_Metric();
  $metric->setExpression("ga:pageviews");

  //ページごとにデータを取得
  $dimention = new Google_Service_AnalyticsReporting_Dimension();
  $dimention->setName("ga:pagePath");

  ///post/で始まるパスのページのみ取得
  $filter = new Google_Service_AnalyticsReporting_DimensionFilter();
  $filter->setDimensionName("ga:pagePath");
  $filter->setOperator("BEGINS_WITH");
  $filter->setExpressions( ["/post/"] );

  //フィルタをセット
  $clause = new Google_Service_AnalyticsReporting_DimensionFilterClause();
  $clause->setFilters(array($filter));

  //PV降順でデータを取得
  $orderby = new Google_Service_AnalyticsReporting_OrderBy();
  $orderby->setFieldName("ga:pageviews");
  $orderby->setSortOrder("DESCENDING");

  //上記設定をまとめる
  $request = new Google_Service_AnalyticsReporting_ReportRequest();
  $request->setViewId(VIEW_ID);
  $request->setDateRanges($dateRange);
  $request->setMetrics(array($metric));
  $request->setDimensions(array($dimention));
  $request->setDimensionFilterClauses($clause);
  $request->setOrderBys($orderby);

  //データを取得する準備
  $body = new Google_Service_AnalyticsReporting_GetReportsRequest();
  $body->setReportRequests( array( $request) );

  //実際にデータを取得
  $response = $analytics->reports->batchGet( $body );
  
  //戻り値のメインデータを取り出す
  $rows = $response[0]->getData()->getRows();

  //返すデータを格納する配列
  $data = array();

  //APIのデータとWordPressの記事IDを関連づける
  foreach ( $rows as $row ) {
    $path = $row["dimensions"][0];
    $pv = $row["metrics"][0]["values"][0];
    $url = home_url($path);
    $id = url_to_postid($url);
    
    $data[$id] = $pv;
  }
  
  return $data;
}

次に、アクションフックで、日付変更を検知した時のみAPIを叩くコード↓をfunctions.phpに追加。


date_default_timezone_set('Asia/Tokyo');

define("ORE_PV_LIST", "ore_pv_list");
define("ORE_PV_DATE", "ore_pv_date");
define("ORE_PV_VALUE", "ore_pv_value");

add_action('wp_head', function () {
  $home_id = get_option("page_on_front");
  
  $today = date("Ymd");
  $date = get_post_meta($home_id, ORE_PV_DATE, true);
  
  if ( strcmp($today, $date) != 0 ) {
    $data = get_pv_from_api();
    
    update_post_meta($home_id, ORE_PV_DATE, $today);
    update_post_meta($home_id, ORE_PV_LIST, $data);
    
    foreach ($data as $id => $pv) {
      update_post_meta($id, ORE_PV_VALUE, $pv);
    }
  }
});

最後に、オススメ記事表示部分でカスタムフィールドからデータを呼び出す。


$query = array(
        'post_type' => 'post', 
        'post_status' => 'publish', 
        'posts_per_page' => 5,
        'orderby' => 'meta_value_num',
        'order' => 'DESC',
        'meta_key' => ORE_PV_VALUE,
);

$posts = new WP_Query($query);

以上、WordPressからお届けしました!

シェアする: