Googleアナリティクス タグマネージャー設定

ECサイト(WooCommerce)で「商品が見られているか」「カートに入れたのに買われていないか」を数値で追えるようにするため、Googleタグマネージャー(GTM)経由でGA4にeコマースイベントを送る設定を行いました。あわせて、自分自身の作業アクセスがデータに混ざらないよう内部トラフィックの除外も設定しています。同じことをやりたい人向けに、手順とハマったポイントをまとめます。

対象読者:WordPress(WooCommerce)サイトの運営者・実装者で、GA4のeコマースレポート(商品別の閲覧・カート追加・購入)を使えるようにしたい人。

以下、サイトの独自情報(ドメイン、測定ID、IPアドレスなど)はすべて置き換え済みのサンプル値です。実際に設定する際は、ご自身の値に読み替えてください。

全体構成

WooCommerceでの行動(商品閲覧・カート追加・購入など)
  ↓(テーマ/プラグインがdataLayerに出力)
dataLayer(ブラウザ上の一時的なデータ置き場)
  ↓(GTMのトリガーが検知)
GTM(Googleタグマネージャー)
  ↓(GA4イベントタグが送信)
GA4(Googleアナリティクス4)

GTMの役割は「WordPress側が出したデータをGA4まで届ける」ところまでです。届いた後のレポート表示(ダッシュボード化など)は別の話になります。

1. サイトへのGTM設置

<head>内のできるだけ上の方に、GTMのコンテナスニペットを設置します。

<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
<!-- End Google Tag Manager -->

<body>タグの直後にnoscript用のタグも設置します(JavaScriptが無効な環境向け)。

<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->

GTM側では、測定ID(G-XXXXXXXXXX)を指定した「Googleタグ」を作成し、トリガーを「All Pages(すべてのページ)」に設定してページビュー計測用のタグを用意しておきます。

2. WooCommerceの行動をdataLayerに出力する

GA4は、WooCommerceがカートや注文をどう扱っているかを自動的には知りません。そのため、以下の4つのタイミングでWordPress側からdataLayerにイベントを送る実装が必要です。

イベント名 タイミング
view_item 商品詳細ページの閲覧
add_to_cart カートに追加
begin_checkout 購入手続き開始(チェックアウトページ表示)
purchase 購入完了(サンクスページ表示)

これは自作の軽量プラグインとして実装しました(テーマに直接書くと、テーマをバージョンアップ・コピーするたびに再実装が必要になるため)。主なポイントだけ抜粋します。

view_item(商品詳細ページ)

function sge_output_view_item() {
    if ( ! is_product() ) {
        return;
    }
    global $product;
    if ( ! $product instanceof WC_Product ) {
        return;
    }
    $item = sge_get_item_data( $product );
    sge_render_ecommerce_script( 'view_item', array(
        'currency' => get_woocommerce_currency(),
        'value'    => $item['price'],
        'items'    => array( $item ),
    ) );
}

add_to_cart(カート追加)

ここが一番ハマりやすいポイントでした。詳細は後述の「つまずいたポイント」を参照してください。AJAX追加とAJAXを使わない通常送信の両方に対応するため、2つの仕組みを併用しています。

  • 一覧ページなどのAJAX追加ボタン → WooCommerceが発火するadded_to_cartというjQueryイベントを利用してJavaScript側でdataLayerにpush
  • 商品詳細ページ等の通常フォーム送信 → PHP側のwoocommerce_add_to_cartアクションで検知し、WooCommerceのセッションに一時保存 → 次のページ表示時(wp_footer)に出力
// AJAXを使わない通常送信の場合の受け皿
function sge_store_add_to_cart_event( $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data ) {
    if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
        return; // AJAX分はJS側で既に計測済みなので除外
    }
    if ( ! WC()->session ) {
        return;
    }
    $product = wc_get_product( $variation_id ? $variation_id : $product_id );
    $item    = sge_get_item_data( $product, $quantity );
    WC()->session->set( 'sge_pending_add_to_cart', $item );
}

function sge_output_add_to_cart_fallback() {
    if ( ! WC()->session ) {
        return;
    }
    $item = WC()->session->get( 'sge_pending_add_to_cart' );
    if ( ! $item ) {
        return;
    }
    WC()->session->__unset( 'sge_pending_add_to_cart' );
    sge_render_ecommerce_script( 'add_to_cart', array(
        'currency' => get_woocommerce_currency(),
        'value'    => $item['price'] * $item['quantity'],
        'items'    => array( $item ),
    ) );
}

begin_checkout(チェックアウトページ)

function sge_output_begin_checkout() {
    if ( ! WC()->cart || WC()->cart->is_empty() ) {
        return;
    }
    $items = array();
    foreach ( WC()->cart->get_cart() as $cart_item ) {
        $items[] = sge_get_item_data( $cart_item['data'], $cart_item['quantity'] );
    }
    sge_render_ecommerce_script( 'begin_checkout', array(
        'currency' => get_woocommerce_currency(),
        'value'    => (float) WC()->cart->get_subtotal(),
        'items'    => $items,
    ) );
}

purchase(購入完了)

サンクスページの再読み込みで二重計測しないよう、注文ごとに送信済みフラグを記録しています。

function sge_output_purchase( $order_id ) {
    if ( get_post_meta( $order_id, '_sge_purchase_tracked', true ) ) {
        return; // 二重計測防止
    }
    $order = wc_get_order( $order_id );
    // ...注文の商品情報を組み立ててdataLayerへpush...
    update_post_meta( $order_id, '_sge_purchase_tracked', 1 );
}

3. GTM側:トリガーとタグの設定

WordPress側の実装だけではGA4にデータは届きません。GTM側で「dataLayerに来たイベントを検知して、GA4に送る」設定が必要です。

  1. トリガーを作成:タイプ「カスタムイベント」、イベント名を正規表現一致にして以下を指定
    ^(view_item|add_to_cart|begin_checkout|purchase)$
  2. タグを作成:タグの種類「GA4 イベント」、イベント名に組み込み変数{{Event}}を指定、「eコマースデータを送信する」をオンにし、上記トリガーで発火するよう設定

こうすることで、4つのイベントを1つのトリガー・1つのタグでまとめて処理できます。

つまずいたポイント

(1) is_woocommerce()のタイミング問題

プラグインの冒頭に以下のようなガード処理を書いたところ、WooCommerceが有効なのに常に処理が止まってしまいました。

// ダメな例
if ( ! function_exists( 'is_woocommerce' ) ) {
    return;
}

原因は、WooCommerce本体がこの関数を定義するのがplugins_loadedというタイミングであるのに対し、上記のチェックはプラグインファイルが読み込まれる最初の瞬間(plugins_loadedより前)に実行されてしまうためです。フックの登録はplugins_loaded以降に行うよう修正しました。

add_action( 'plugins_loaded', 'sge_register_hooks' );
function sge_register_hooks() {
    if ( ! function_exists( 'is_woocommerce' ) ) {
        return;
    }
    add_action( 'wp_footer', 'sge_output_view_item' );
    // ...他のフックもここに登録...
}

(2) カート追加後のリダイレクト設定

WooCommerceの設定「カートに追加後、カートページへ自動的に移動する」がオンの場合、URLに?added-to-cart=商品IDが付与されないため、URLパラメータを見て判定する方式では検知できません。この設定の有無に関わらず動くよう、WooCommerceのセッションを使う方式(上記のwoocommerce_add_to_cartアクション経由)に変更しました。

4. 動作確認

GTMの「プレビュー」機能(Tag Assistant)を使うと、実際にサイトを操作しながらどのイベントがdataLayerに届き、どのタグが発火したかをリアルタイムで確認できます。

  • ブラウザの開発者ツール(Console)でdataLayerと入力すると、実際に送られた内容を直接確認できるので、Tag Assistant側の表示と食い違う場合の切り分けに有効です

5. 内部トラフィックの除外設定(GA4)

自分自身の作業アクセス(動作確認や管理業務)がデータに混ざると、コンバージョン率などの数値が歪みます。GA4の管理画面で以下の設定を行いました。

手順1:内部トラフィックの定義

  1. GA4管理画面 →「データストリーム」→ 対象のウェブストリームをクリック
  2. 「Googleタグ」欄の「タグ設定を行う」をクリック
  3. 「詳細設定を表示」の中から「内部トラフィックを定義する」をクリック
  4. 「作成」をクリックし、以下を入力
    ルール名 自宅(分かりやすい名前でOK)
    traffic_typeの値 internal
    一致演算子 IPアドレスが次と等しい
    値 xxx.xxx.xxx.xxx(自分の現在のIPアドレス)
  5. 「作成」で保存

自分の現在のIPアドレスは「IPアドレス確認」などで検索すると調べられます。家庭用回線の多くは固定IPではないため、IPアドレスが変わると設定が効かなくなる点に注意が必要です。

手順2:データフィルタの作成

  1. GA4管理画面 →「データ設定」→「データフィルタ」
  2. 「作成」をクリック
  3. フィルタの種類「内部トラフィック」を選択
  4. フィルタ名を入力し、パラメータ値に「internal」(手順1と同じ値)を指定
  5. 運用状況は最初「テスト中」にして様子を見てから「有効」に切り替える

まとめ

  • GTMの役割は「WordPress側のデータをGA4に届ける」ところまで。レポートでの分析は別工程
  • WooCommerceの行動をGA4に送るには、dataLayerへの出力(WordPress側の実装)とGTM側のトリガー・タグ設定の両方が必要
  • カート追加の計測は、WooCommerceの設定(AJAX有無・カート追加後のリダイレクト有無)によって挙動が変わるため、複数のパターンに対応する実装が必要
  • 内部トラフィックの除外は、IPアドレスに依存するため、固定IPでない場合は定期的な見直しが必要