この記事をおすすめしたい人
- WordPressで前日PVを集計したい人
- アナリティクスに頼らず自分でカウントしたい人
- つまりオレ
WordPressで前日のPVを集計する方法を考えていきます。 「人気の投稿」とかをソートするときにリアルタイム性が出やすくするための数値ですね。
以前同じことをアナリティクスのAPIを使ってやりました。
ところがこの後アナリティクスがメジャーバージョンアップしてしまって使えなくなって、サイトまるごと停止してしまってたので、今回は外部に頼らずにfunctions.phpに書いていこうと思います。
ChatGPTがな!
処理の大まかな流れ
処理の流れはこう↓決めました。
- 閲覧ごとに当日のPVをカウント
- 24時になったら当日PVを前日PVに移して当日PVを初期化
PVのカウントはWP-PostViewsってのを使ってて、ソース見ればやり方わかるでしょう。
毎日24時で処理するのはCRONだっけ、なんかあったと思います。 全然わかんないのでChatGPTくんに聞こう。
あとは、投稿一覧の画面で表示したいな。 できればソート機能もつけたいな。
みたいな感じでやってこうと思います。
先に必要な定数を定義
こんな↓感じで処理に必要な定数を決めました。
//当日のPVを記録するカスタムフィールドの名前
define('TODAY_PV_KEY', 'today_pv_count');
//前日のPVを記録するカスタムフィールドの名前
define('YESTERDAY_PV_KEY', 'yesterday_pv_count');
//PVリセットのスケジュール用フックの名前
define('PV_RESET_HOOK', 'reset_pv_count');
//PVリセットを実行する時間
define('PV_RESET_TIME', 'today 24:00');
//投稿一覧に表示する「当日PV」列の名前
define('TODAY_PV_COLUMN', 'today_pv');
//投稿一覧に表示する「前日PV」列の名前
define('YESTERDAY_PV_COLUMN', 'yesterday_pv');
ハードコードを避けるためなので好きな名前でおkです。
PV_RESET_TIMEは集計を終える時間で、上だと深夜0時に実行されます。 これだと夜更かししてる人を考慮できないので僕は「tomorrow 5:00 am」で明け方5時にしています。
まずはPVをカウントする
WP-PostViewsのソースを見たらwp_headでフックしてたので真似してこう↓なりました。
add_action('wp_head', function () {
if ( is_user_logged_in() || !is_singular() ) return;
global $post;
$id = $post ? $post->ID : null;
if ( empty($id) ) return;
$pv = get_post_meta($id, TODAY_PV_KEY, true);
if ( empty($pv) ) {
add_post_meta($id, TODAY_PV_KEY, '0');
add_post_meta($id, YESTERDAY_PV_KEY, '0');
} else {
update_post_meta($id, TODAY_PV_KEY, $pv+1);
}
});
「is_user_logged_in」でログインユーザをカウントしないようにしています。
「is_singular」というのは投稿ページ、固定ページ、カスタム投稿タイプで真が返る関数らしくてChatGPTくんに教えてもらいました。 詳細は調べてません。
次に現在の投稿を取得してIDが取得できれば処理続行。 取得できなければ終了。
現在の投稿から当日PVのカスタムフィールドを取得。 取得できればカウントを+1して保存。 取得できなければ初アクセスということで、当日PVと前日PVのカスタムフィールドを追加。
指定した時間でPVをリセット
まず実行される処理部分↓を作っておきます。
add_action(PV_RESET_HOOK, function () {
$posts = get_posts(array(
'post_type' => 'any',
'posts_per_page' => -1,
'fields' => 'ids',
));
foreach ( $posts as $id ) {
$pv = get_post_meta($id, TODAY_PV_KEY, true);
update_post_meta($id, YESTERDAY_PV_KEY, $pv);
update_post_meta($id, TODAY_PV_KEY, '0');
}
});
全投稿を取得してループを回し、当日PVを取得。 それを前日PVにセット、当日PVを初期化です。
これだと投稿数1000とかいくと重くならない?って聞くとやっぱりなるらしくて、その場合はSQLで直接いじればいいよって教えてもらったんですがSQL苦手なので今回は断念。
次にこの処理をスケジュールにセット↓します。
if ( !wp_next_scheduled(PV_RESET_HOOK) ) {
wp_schedule_event(strtotime(PV_RESET_TIME), 'daily', PV_RESET_HOOK);
}
wp_next_scheduledでスケジュールに登録済みかをチェックし、されてなければwp_schedule_eventで登録してます。 「daily」の部分は周期を表すそうで、週1とか月1とかもできるらしいです。
投稿一覧で表示
この辺ほとんどやったことないので全部ChatGPTくん任せです。 簡単な動作確認はしています。
まず投稿一覧に表示列を追加↓します。
add_filter('manage_posts_columns', function($columns) {
$columns[TODAY_PV_COLUMN] = '当日PV';
$columns[YESTERDAY_PV_COLUMN] = '前日PV';
return $columns;
});
今考えるとここも定数定義しとくべきでしたね。
次に個々の投稿で追加した列に表示する部分↓を作ります。
add_action('manage_posts_custom_column', function($name, $id) {
if ( $name == TODAY_PV_COLUMN ) {
$pv = get_post_meta($id, TODAY_PV_KEY, true);
echo $pv ? $pv : '0';
}
if ( $name == YESTERDAY_PV_COLUMN ) {
$pv = get_post_meta($id, YESTERDAY_PV_KEY, true);
echo $pv ? $pv : '0';
}
}, 10, 2);
次に登録した列をソート可能な列として登録します。
add_filter('manage_edit-post_sortable_columns', function($columns) {
$columns[TODAY_PV_COLUMN] = TODAY_PV_COLUMN;
$columns[YESTERDAY_PV_COLUMN] = YESTERDAY_PV_COLUMN;
return $columns;
});
「manage_edit-post_sortable_columns」は「投稿ページ」専用なので、固定ページの場合は「manage_edit-page_sortable_columns」に変更するか、それ用を追加しないといけません。
最後にソートの処理を追加↓して終わり。
add_action('pre_get_posts', function($query) {
if ( !is_admin() ) return;
$orderby = $query->get('orderby');
if ( $orderby == TODAY_PV_COLUMN ) {
$query->set('meta_key', TODAY_PV_KEY);
$query->set('orderby', 'meta_value_num');
} elseif ( $orderby == YESTERDAY_PV_COLUMN ) {
$query->set('meta_key', YESTERDAY_PV_KEY);
$query->set('orderby', 'meta_value_num');
}
});
まとめ
ここまでのコードをまとめるとこう↓なります。
define('TODAY_PV_KEY', 'today_pv_count');
define('YESTERDAY_PV_KEY', 'yesterday_pv_count');
define('PV_RESET_HOOK', 'reset_pv_count');
define('PV_RESET_TIME', 'today 24:00');
define('TODAY_PV_COLUMN', 'today_pv');
define('YESTERDAY_PV_COLUMN', 'yesterday_pv');
add_action('wp_head', function () {
if ( is_user_logged_in() || !is_singular() ) return;
global $post;
$id = $post ? $post->ID : null;
if ( empty($id) ) return;
$pv = get_post_meta($id, TODAY_PV_KEY, true);
if ( empty($pv) ) {
add_post_meta($id, TODAY_PV_KEY, '0');
add_post_meta($id, YESTERDAY_PV_KEY, '0');
} else {
update_post_meta($id, TODAY_PV_KEY, $pv+1);
}
});
add_action(PV_RESET_HOOK, function () {
$posts = get_posts(array(
'post_type' => 'any',
'posts_per_page' => -1,
'fields' => 'ids',
));
foreach ( $posts as $id ) {
$pv = get_post_meta($id, TODAY_PV_KEY, true);
update_post_meta($id, YESTERDAY_PV_KEY, $pv);
update_post_meta($id, TODAY_PV_KEY, '0');
}
});
if ( !wp_next_scheduled(PV_RESET_HOOK) ) {
wp_schedule_event(strtotime(PV_RESET_TIME), 'daily', PV_RESET_HOOK);
}
add_filter('manage_posts_columns', function($columns) {
$columns[TODAY_PV_COLUMN] = '当日PV';
$columns[YESTERDAY_PV_COLUMN] = '前日PV';
return $columns;
});
add_action('manage_posts_custom_column', function($name, $id) {
if ( $name == TODAY_PV_COLUMN ) {
$pv = get_post_meta($id, TODAY_PV_KEY, true);
echo $pv ? $pv : '0';
}
if ( $name == YESTERDAY_PV_COLUMN ) {
$pv = get_post_meta($id, YESTERDAY_PV_KEY, true);
echo $pv ? $pv : '0';
}
}, 10, 2);
add_filter('manage_edit-post_sortable_columns', function($columns) {
$columns[TODAY_PV_COLUMN] = TODAY_PV_COLUMN;
$columns[YESTERDAY_PV_COLUMN] = YESTERDAY_PV_COLUMN;
return $columns;
});
add_action('pre_get_posts', function($query) {
if ( !is_admin() ) return;
$orderby = $query->get('orderby');
if ( $orderby == TODAY_PV_COLUMN ) {
$query->set('meta_key', TODAY_PV_KEY);
$query->set('orderby', 'meta_value_num');
} elseif ( $orderby == YESTERDAY_PV_COLUMN ) {
$query->set('meta_key', YESTERDAY_PV_KEY);
$query->set('orderby', 'meta_value_num');
}
});
PV_RESET_TIMEで更新時間だけ設定したらこのままコピペで使えると思います。 24時でよければこのままでおk。