とてもニッチなお話ですが、
WordPressで記事を投稿する際に、
上位のアカウントだと自分以外の投稿者を選ぶ事ができる。
ただこの項目、全てのユーザーを表示名順に並べただけのドロップダウンリストになっていて、
沢山のユーザー登録があるとエライコッチャな事になってしまう。
せめて、このリストを綺麗な順番に並び替えておきたい。
目標
漢字を含む、投稿者のドロップダウンリストを綺麗な五十音順にする。
さっそく初めます
フリガナを保存するフィールドを作る
WordPressのユーザー情報は wp_users
というテーブルに保存されている。
五十音順の第一歩として、ここにフリガナを保存する kana
というフィールドを作る。
本来であれば、ユーザー登録画面でフリガナも入力できる様にするべきだけど、
今回はまず現状を打破したくて、とりあえずフリガナの入力も含めて直接済ませた。
プルダウンリストのソートを変更する
管理画面のHTMLを覗くと post_author_override
という名前でリストを生成しているらしい。
それをWordPressの本体で検索して辿って行くと、wp-includes/user.php
にそれらしい物をみつけた。
//1498行目付近
function wp_dropdown_users( $args = '' ) {
$defaults = array(
'show_option_all' => '', 'show_option_none' => '', 'hide_if_only_one_author' => '',
'orderby' => 'display_name', 'order' => 'ASC',
'include' => '', 'exclude' => '', 'multi' => 0,
'show' => 'display_name', 'echo' => 1,
'selected' => 0, 'name' => 'user', 'class' => '', 'id' => '',
'blog_id' => $GLOBALS['blog_id'], 'who' => '', 'include_selected' => false,
'option_none_value' => -1
);
//以下略
'orderby' => 'display_name'
とある!
display_name
は wp_users
で見たところズバリ表示名の様で、ここを kana
に修正すれば解決するのでは!
//修正後
function wp_dropdown_users( $args = '' ) {
$defaults = array(
'show_option_all' => '', 'show_option_none' => '', 'hide_if_only_one_author' => '',
'orderby' => 'kana', 'order' => 'ASC',
'include' => '', 'exclude' => '', 'multi' => 0,
'show' => 'display_name', 'echo' => 1,
'selected' => 0, 'name' => 'user', 'class' => '', 'id' => '',
'blog_id' => $GLOBALS['blog_id'], 'who' => '', 'include_selected' => false,
'option_none_value' => -1
);
//以下略
解決しなかった
すると、フリガナでも表示名でもなく、何故か user_login
(ログインID)でソートされる様になった。
コードをそのまま読み進めると、どうも get_users
という物の中で指定の要素以外の場合 user_login
に修正する処理が行われている様だった。
改めてCodexを読むと、ちゃんと説明が書かれていた。
orderby - ソート順を決める項目。有効な値は 'ID', 'login', 'nicename', 'email', 'url', 'registered', 'display_name', 'post_count', または 'meta_value'。
WordPress Codex 日本語版 関数リファレンス/get users
後から追加したフィールド kana
が含まれているハズもなく。
なんとか有効な値以外でも見逃してくれる様にしたい。
kana
を有効な値にする
調べていくと、parse_orderby
という物をみつけた。
その時の $orderby
に合わせて正しいものを入れなおす物らしい。
//960行目付近
protected function parse_orderby( $orderby ) {
global $wpdb;
$meta_query_clauses = $this->meta_query->get_clauses();
$_orderby = '';
if ( in_array( $orderby, array( 'login', 'nicename', 'email', 'url', 'registered' ) ) ) {
$_orderby = 'user_' . $orderby;
} elseif ( in_array( $orderby, array( 'user_login', 'user_nicename', 'user_email', 'user_url', 'user_registered' ) ) ) {
$_orderby = $orderby;
} elseif ( 'name' == $orderby || 'display_name' == $orderby ) {
$_orderby = 'display_name';
} elseif ( 'post_count' == $orderby ) {
// todo: avoid the JOIN
$where = get_posts_by_author_sql( 'post' );
$this->query_from .= " LEFT OUTER JOIN (
SELECT post_author, COUNT(*) as post_count
FROM $wpdb->posts
$where
GROUP BY post_author
) p ON ({$wpdb->users}.ID = p.post_author)
";
$_orderby = 'post_count';
} elseif ( 'ID' == $orderby || 'id' == $orderby ) {
$_orderby = 'ID';
} elseif ( 'meta_value' == $orderby || $this->get( 'meta_key' ) == $orderby ) {
$_orderby = "$wpdb->usermeta.meta_value";
} elseif ( 'meta_value_num' == $orderby ) {
$_orderby = "$wpdb->usermeta.meta_value+0";
} elseif ( 'include' === $orderby && ! empty( $this->query_vars['include'] ) ) {
$include = wp_parse_id_list( $this->query_vars['include'] );
$include_sql = implode( ',', $include );
$_orderby = "FIELD( $wpdb->users.ID, $include_sql )";
} elseif ( isset( $meta_query_clauses[ $orderby ] ) ) {
$meta_clause = $meta_query_clauses[ $orderby ];
$_orderby = sprintf( "CAST(%s.meta_value AS %s)", esc_sql( $meta_clause['alias'] ), esc_sql( $meta_clause['cast'] ) );
}
return $_orderby;
}
何にも当てはまらない場合、空の要素を返す様で、
呼び出し元のほうで、空の場合 user_login
を入れる様な仕組みになっていた。
かなり強引だけど、ここに kana
の場合の処理を入れたら動きそうだ。
//960行目付近
protected function parse_orderby( $orderby ) {
global $wpdb;
$meta_query_clauses = $this->meta_query->get_clauses();
$_orderby = '';
if ( in_array( $orderby, array( 'login', 'nicename', 'email', 'url', 'registered' ) ) ) {
$_orderby = 'user_' . $orderby;
} elseif ( in_array( $orderby, array( 'user_login', 'user_nicename', 'user_email', 'user_url', 'user_registered' ) ) ) {
$_orderby = $orderby;
} elseif ( 'name' == $orderby || 'display_name' == $orderby ) {
$_orderby = 'display_name';
} elseif ( 'post_count' == $orderby ) {
// todo: avoid the JOIN
$where = get_posts_by_author_sql( 'post' );
$this->query_from .= " LEFT OUTER JOIN (
SELECT post_author, COUNT(*) as post_count
FROM $wpdb->posts
$where
GROUP BY post_author
) p ON ({$wpdb->users}.ID = p.post_author)
";
$_orderby = 'post_count';
} elseif ( 'ID' == $orderby || 'id' == $orderby ) {
$_orderby = 'ID';
} elseif ( 'meta_value' == $orderby || $this->get( 'meta_key' ) == $orderby ) {
$_orderby = "$wpdb->usermeta.meta_value";
} elseif ( 'meta_value_num' == $orderby ) {
$_orderby = "$wpdb->usermeta.meta_value+0";
} elseif ( 'include' === $orderby && ! empty( $this->query_vars['include'] ) ) {
$include = wp_parse_id_list( $this->query_vars['include'] );
$include_sql = implode( ',', $include );
$_orderby = "FIELD( $wpdb->users.ID, $include_sql )";
} elseif ( isset( $meta_query_clauses[ $orderby ] ) ) {
$meta_clause = $meta_query_clauses[ $orderby ];
$_orderby = sprintf( "CAST(%s.meta_value AS %s)", esc_sql( $meta_clause['alias'] ), esc_sql( $meta_clause['cast'] ) );
} elseif ( 'kana' == $orderby ) { //追加
$_orderby = $orderby; //追加
}
return $_orderby;
}
こんな感じかな。
一応ちゃんと動いた
ここまで行うと、なんとか想定通りにうごいてくれた。
とはいえコアを弄ってしまっている上に、かなり手探りだったのでちょっと怪しいところ。
最後に
これからの目標
- コアを弄らずに同じ動作を実装したい
- ユーザー登録/編集でフリガナを変更できる様にしたい
という訳で、まだまだ手探りなストックにはなりますが、
忌憚の無いご意見や、アドバイスなどお聞きできれば有難いです。
引き続き勉強して、何か気がついた所があれば追記・編集していきます。