Google アナリティクスのデータを使い WordPress で人気ランキングを作る

Akira

福岡在住の Web デザイナー。Web サイト制作に役立つ情報を紹介しています。AMP が大好き。

FacebookTwitter で記事の更新をお知らせしています。

はじめに

Google アナリティクスの計測結果を使い、WordPress で人気記事ランキングを作る方法です。使用するのは アナリティクス Reporting API v4

使い方を忘れそうなため、記事として残しておきます。

PHP でのアナリティクス Reporting API v4 の基本的な使い方は、公式のはじめてのアナリティクス Reporting API v4: サービス アカウント向け PHP クイックスタートに書かれています。

やりたかったこと

頭に浮かんだのは、集計期間が異なる複数の人気記事ランキングを作ること。その複数のランキングをタブで切り替えての表示をイメージしました。Building a Tabs component を見た直後で影響を受けています。

ただ、複数のランキングを作るとは限らないため、集計期間が1つの時にも対応したいと考えました。

プロジェクトの作成と連携

アナリティクス Reporting API v4 を使うには、まず Google Cloud Platform の Google API Console でプロジェクトを作成します。利用料金は無料です。リクエストの割り当ては、アナリティクス Reporting API v4 – API リクエストの制限と割り当てを参照してください。

また、プロジェクトの作成後は、連携するために Google アナリティクスへのユーザーの追加が必要です。

プロジェクトの作成と Google アナリティクスへのユーザーの追加については、【2019年版】Google Analytics API v4 の使い方(PHP)に詳しく書かれています。2019年版とありますが、2021年4月時点でもそのまま参考にできます。以下は、各見出しへのリンクです。

ライブラリのインストール

次は、PHP 版 Google API クライアントライブラリComposer を使用しインストールします。

ライブラリを設置する階層に composer.json ファイルを作成し、このように書きました。

{
  "require": {
    "google/apiclient": "^2.7"
  }
}

バージョンの指定は、Github を参考にしています。

そしてインストールします。

$ composer install

尚、Composer を使用せず、任意のバージョンをダウンロードしての使用も可能です。公式の説明は、Download the Release をご覧ください。

秘密鍵のアップロード

Google API Console でのプロジェクト作成後にダウンロードした秘密鍵をアップロードします。アップロード場所は、composer.json と同じ階層にしました。ファイル名は、service-account-credentials.json にします。

cacert.pem のダウンロードとアップロード

Windows 10 の環境でコードを書いていると下記のエラーが出ました。

Fatal error: Uncaught GuzzleHttp\Exception\RequestException: cURL error 60: SSL certificate problem: unable to get local issuer certificate (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://oauth2.googleapis.com/token in ******\vendor\guzzlehttp\guzzle\src\Handler\CurlFactory.php on line 211

調べると 2 つの参考情報がありました。

証明書の検証をしない解決方法もあるようですが、今回は証明書をダウンロードする方法を採用しました。

http://curl.haxx.se/ca/cacert.pem から証明書をダウンロードし、composer.json と同じ階層にアップロードします。

コード

ここからコードを書いていきます。このような考えで書いていきました。

  • WordPress では URL が分かれば投稿ページの様々なデータを取得できるため、Google アナリティクスから取得するのは ga:pagePath のみ。
  • ページビュー数(ga:pageviews)が多い順に取得する。
  • 集計期間が複数であっても1つであっても対応できるようにする。
  • アナリティクス Reporting API v4 の無料枠のリクエスト数に制限があること、またページの表示速度の観点から、取得するアナリティクスのデータを WordPress Transients API を使い一定期間データベースに保存する(実際に保存したのは HTML)。

書いたコードは、このようなものです。functions.php に追加します。基本的に公式のサンプルのまま書いていますが、関数の引数は変更しています。

require_once '/vendor/autoload.php のパスを入力';

/**
 * アナリティクス Reporting API v4 の初期化
 */
function initializeAnalytics() {
  $key_file_location = '/service-account-credentials.json のパスを入力';

  // GuzzleHttp の検証
  // cURL error 60: SSL certificate problem への対応
  $http = new GuzzleHttp\Client([
    'verify' => '/cacert.pem のパスを入力'
  ]);

  $client = new Google_Client();
  // GuzzleHttp の検証
  $client->setHttpClient($http);
  $client->setApplicationName('Analytics Ranking');
  $client->setAuthConfig($key_file_location);
  $client->setScopes(['https://www.googleapis.com/auth/analytics.readonly']);
  $analytics = new Google_Service_AnalyticsReporting($client);

  return $analytics;
}

/**
 * アナリティクス Reporting API v4 への要求
 * 引数は集計期間の開始日を指定する
 */
function getReport($start_date) {
  $view_id = 'Google アナリティクスのビュー ID を入力';

  // 集計期間の指定
  $dateRange = new Google_Service_AnalyticsReporting_DateRange();
  $dateRange->setStartDate($start_date);
  $dateRange->setEndDate('today');

  // 指標はページビュー数とする
  $pageviews = new Google_Service_AnalyticsReporting_Metric();
  $pageviews->setExpression('ga:pageviews');
  $pageviews->setAlias('pageviews');

  // ディメンションはページ URI とする
  $dimention = new Google_Service_AnalyticsReporting_Dimension();
  $dimention->setName('ga:pagePath');

  // 除外ページの指定
  $filter = new Google_Service_AnalyticsReporting_DimensionFilter();
  // ga:pagePath で除外ページを指定する
  $filter->setDimensionName('ga:pagePath');
  $filter->setNot(true);
  $filter->setOperator('IN_LIST');
  // bit_exclude_analytics() で除外ページを設定する
  $filter->setExpressions(bit_exclude_analytics());

  $filters = new Google_Service_AnalyticsReporting_DimensionFilterClause();
  $filters->setFilters([$filter]);

  // ページビュー数の多い順で取得する
  $orderby = new Google_Service_AnalyticsReporting_OrderBy();
  $orderby->setFieldName('ga:pageviews');
  $orderby->setOrderType('VALUE');
  $orderby->setSortOrder('DESCENDING');

  // アナリティクスへの要求
  $request = new Google_Service_AnalyticsReporting_ReportRequest();
  $request->setViewId($view_id);
  $request->setDateRanges([$dateRange]);
  $request->setMetrics([$pageviews]);
  $request->setDimensions([$dimention]);
  $request->setDimensionFilterClauses([$filters]);
  $request->setOrderBys([$orderby]);
  // 取得件数の指定(10件取得)
  $request->setPageSize(10);

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

  return initializeAnalytics()->reports->batchGet($body);
}

/**
 * アナリティクスデータの表示
 * 引数は集計期間の開始日を指定する
 */
function printResults($start_date) {
  $transient = 'bit_popular_html_';
  $transient .= $start_date;
  $html = get_transient($transient);

  if ($html === false) {
    $report = getReport($start_date)[0];
    $rows = $report->getData()->getRows();

    ob_start();
    echo '<ol>';
    for ($rowIndex = 0; $rowIndex < count($rows); ++$rowIndex) {
      $row = $rows[$rowIndex];
      $dimensions = $row->getDimensions();
      $url = home_url();
      $url .= $dimensions[0];
      $id = url_to_postid($url);
      $title = get_the_title($id);
      $cats = get_the_category($id);
      $cat_name = (! empty($cats)) ? $cats[0]->cat_name : '未登録';
      ?>
      <li>
        <h3><?php echo $title; ?></h3>
        <p><?php echo $cat_name; ?></p>
        <p><a href="<?php echo $url; ?>">記事を読む</a></p>
      </li>
      <?php
    }
    echo '</ol>';
    $html = ob_get_clean();
    // 1日間データベースに保存する
    set_transient($transient, $html, DAY_IN_SECONDS);
  }

  return $html;
}

/**
 * アナリティクスデータから除外するページの設定
 * 除外ページを配列で返す
 */
function bit_exclude_analytics() {
  $path = [];

  // トップページを除外する
  $path[] = '/';

  // 全てのカテゴリーページを除外する
  // サイトによってカテゴリーページまでの URL が異なるため get_categories() の戻り値 slug は使わない
  $cats = get_categories();
  foreach ($cats as $cat) {
    $path[] = get_category_link($cat->cat_ID);
  }

  // 全ての固定ページを除外する
  // 除外したくないページがあれば get_pages() のパラメータ exclude を使用する
  // サイトによってパーマリンクが異なるため get_pages() の戻り値 post_name は使わない
  $pages = get_pages();
  if ($pages !== false) {
    foreach ($pages as $page) {
      $path[] = get_permalink($page->ID);
    }
  }

  // 他に除外するページがあれば $path に追加する

  // ga:pagePath で除外するため置換し返す
  return str_replace(home_url(), '', $path);
}

1行目・7行目・12行目・31行目は、サイトに合わせて変更します。また、アイキャッチ画像や抜粋などを取得する場合は変更します。

最後に、ランキングを表示したい場所に printResults() を追加します。

<h2>デイリーランキング</h2>
<?php echo printResults('yesterday'); ?>

<h2>週間ランキング</h2>
<?php echo printResults('7daysAgo'); ?>

<h2>月間ランキング</h2>
<?php echo printResults('30daysAgo'); ?>

<h2>2021年ランキング</h2>
<?php echo printResults('2021-01-01'); ?>

printResults() の引数には、集計期間の開始日を指定します。日付は、yesterday7daysAgo など相対的な指定のほか、YYYY-MM-DD 形式での指定も可能です。

結果

実際に表示したところ、無事にアナリティクスの計測結果と同じランキングが表示されました。

また、データベースに保存したデータ(Transient)は、wp_options で確認できます。

Transient は指定した期間を経過後に自動的に削除されますが、delete_transient() を使えば任意のタイミングで削除できます。例えば下記のコードは、WordPress 管理画面 → 外観 → カスタマイズで保存をした時に削除するものです。尚、Transient の名前は bit_popular_html_集計期間の開始日 です。

add_action('customize_save_after', function() {
  // 集計期間の開始日が 7daysAgo の Transient を削除する
  delete_transient('bit_popular_html_7daysAgo');
});

参考情報

最後に、参考にした情報を列挙します(すでにリンクを貼り付けている情報も含まれます)。

送信に失敗しました

ボットと判定された可能性があります。

大変お手数をおかけしますが、以下の内容をご確認の上、再度のコメントの送信をお願い申し上げます。