WP10は弊社が掲げる「WordPressを使った10倍速開発」です。
10倍とは、フルスクラッチに比べて10倍ということです。
この連載ではWP開発に長く携わっている弊社のWordPress開発ベストプラクティスを発信していきます。
第四回はWP_Queryで取得した値をプロパティに格納し、第三回のコードのクエリ数を削減します。
前回のコード
<?php
add_action( 'manage_users_columns', 'add_column_headers' , 10, 3 );
add_action( 'manage_users_custom_column', 'add_column_body', 10, 3 );
/**
* 「投稿タイトル」カラムを追加します
*
* @param $column_headers
*
* @return array
*/function add_column_headers( $column_headers ) {
$column_headers['post_title'] = '投稿タイトル';
return $column_headers;
}
/**
* ユーザーごとの投稿タイトルを表示します
*
* @param $custom_column
* @param $column_name
* @param $user_id
*
* @return string
*/function add_column_body( $custom_column, $column_name, $user_id ) {
// カラムが「入稿タイトル」でない場合は処理を終了する
if ( $column_name !=='post_title' ) {
return;
}
// ユーザーごとの投稿を取得
$query = new WP_Query(
[
'author' => $user_id,
'posts_per_page' => - 1,
'post_type' => 'post',
'post_status' => [
'publish'
]
]
);
// 投稿のタイトルを配列に格納
$post_titles = [];
foreach ( $query->posts as $post ) {
$post_titles[] = $post->post_title;
}
// 配列を文字列に変換
$custom_column = implode( '<br>', $post_titles );
return $custom_column;
}
コードの問題点
フックmanage_users_custom_columnで関数add_column_bodyを動かしています。このフックはユーザーの行ごとに通ります。上記画像ではユーザーは3名なので、このフックには3回通ります。つまり、関数add_column_bodyが3回呼ばれるため、WP_Queryが3回実行されるということです。
ユーザー一覧画面では1ページに表示される最大ユーザー数は20なので、その場合はWP_Queryが20回も動くことになります。クラス化してクエリ数が無駄に増えるのを避けましょう。
クラス化してWP_Queryの結果をプロパティに格納する
<?php
// 上記コードから変更を加えた箇所しか記載していないため、
// このままでは動かないのでご注意ください
class User_List_Extra_Column {
private $query;
public function __construct() {
add_action('manage_users_custom_column', [$this,'add_column_body'], 10, 3);
$this->fetch_all_posts();
}
public function add_column_body($custom_column, $column_name, $user_id) {
// カラムが「入稿タイトル」でない場合は処理を終了する
if ($column_name !== 'post_title') {
return;
}
// 投稿タイトルを配列に格納
$post_titles = [];
foreach ($this->query->posts as $post) {
if ((int)$post->post_author !== $user_id) {
continue;
}
$post_titles[] = $post->post_title;
}
// 配列を文字列に変換
$custom_column = implode('<br>', $post_titles);
return $custom_column;
}
private function fetch_all_posts() {
$query = new WP_Query(
[
'posts_per_page' => - 1,
'post_type' => 'post',
'post_status' => [
'publish'
]
]
);
$this->query = $query;
}
}
fetch_all_postsというメソッドにクエリを全部任せてしまいます。返ってきた結果をprivateプロパティ$queryに格納します。
次に、add_column_bodyメソッドでプロパティを参照し、その投稿がユーザーのものであれば入稿タイトルを配列に格納します。
これでWP_Queryを一度しか呼び出さずに済みました。
効果の検証
クエリ数をデフォルトの状態・前回のコード・今回のコードで比べてみましょう。今回はQuery Monitorというプラグインでクエリ数を測ります。
ユーザーを新しく20名作成します。
デフォルトのクエリ数
Query Monitorの結果は左上の茶色い部分に表示されています。
デフォルトでは29クエリ走っているのがわかります。
前回のコードのクエリ数
前回のコードではなんと89クエリも走っています。
デフォルトでは29クエリなので、89 - 29 = 60。表示されているユーザー数は20なので、1ユーザーに対して3クエリ走っていることになります。
では、今回のコードのクエリ数はいくつでしょうか。
今回のコード
なんと32クエリです。
WP_Queryはコンストラクタで1回呼ばれるだけなので、29 + 3 = 32で3クエリだけ増えているのも納得です。
しっかりクエリ数を削減することができました!
全体のコード
シングルトンパターンにしています。
<?php
User_List_Extra_Column::get_instance();
class User_List_Extra_Column {
private static $instance;
private $query;
public function __construct() {
add_action( 'manage_users_columns', [ $this, 'add_column_headers' ], 10, 3 );
add_action( 'manage_users_custom_column', [ $this, 'add_column_body' ], 10, 3 );
$this->fetch_all_posts();
}
/**
* インスタンス返却します
*
* @return User_List_Extra_Column
*/public static function get_instance() {
if ( !isset( static::$instance ) ) {
static::$instance = new static;
}
return static::$instance;
}
/**
* 投稿タイトル」カラムを追加します
*
* @param $column_headers
*
* @return array
*/public function add_column_headers( $column_headers ) {
$column_headers['post_title'] = '投稿タイトル';
return $column_headers;
}
/**
* ユーザーごとの投稿タイトルを表示します
*
* @param $custom_column
* @param $column_name
* @param $user_id
*
* @return string
*/public function add_column_body( $custom_column, $column_name, $user_id ) {
// カラムが「入稿タイトル」でない場合は処理を終了する
if ( $column_name !== 'post_title' ) {
return;
}
// 投稿タイトルを配列に格納
$post_titles = [];
foreach ( $this->query->posts as $post ) {
if ( (int) $post->post_author !== $user_id ) {
continue;
}
$post_titles[] = $post->post_title;
}
// 配列を文字列に変換
$custom_column = implode( '
', $post_titles );
return $custom_column;
}
/**
* WP_Queryで取得したデータをプロパティに格納します
*/private function fetch_all_posts() {
$query = new WP_Query(
[
'posts_per_page' => - 1,
'post_type' => 'post',
'post_status' => [
'publish'
]
]
);
$this->query = $query;
}
}
WP_Queryが何回も走ってWPが重くなっている場合は、結果をクラスのプロパティに格納しちゃいましょう!
以上、クエリ数の削減についてでした。