記事作成画面、投稿者のドロップダウンリストを自由に並び替える

# とてもニッチなお話ですが、

WordPressで記事を投稿する際に、
上位のアカウントだと自分以外の投稿者を選ぶ事ができる。
ただこの項目、全てのユーザーを表示名順に並べただけのドロップダウンリストになっていて、
沢山のユーザー登録があるとエライコッチャな事になってしまう。
せめて、このリストを綺麗な順番に並び替えておきたい。

## 目標

漢字を含む、投稿者のドロップダウンリストを綺麗な五十音順にする。

## さっそく初めます

### フリガナを保存するフィールドを作る

WordPressのユーザー情報は `wp_users` というテーブルに保存されている。
五十音順の第一歩として、ここにフリガナを保存する `kana` というフィールドを作る。

本来であれば、ユーザー登録画面でフリガナも入力できる様にするべきだけど、
今回はまず現状を打破したくて、とりあえずフリガナの入力も含めて直接済ませた。

### プルダウンリストのソートを変更する

管理画面のHTMLを覗くと `post_author_override` という名前でリストを生成しているらしい。
それをWordPressの本体で検索して辿って行くと、`wp-includes/user.php` にそれらしい物をみつけた。

```php: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` に修正すれば解決するのでは！

```php:wp-includes/user.php
//修正後
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](http://wpdocs.osdn.jp/%E9%96%A2%E6%95%B0%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9/get_users)

後から追加したフィールド `kana` が含まれているハズもなく。
なんとか有効な値以外でも見逃してくれる様にしたい。


### `kana`を有効な値にする

調べていくと、`parse_orderby` という物をみつけた。
その時の `$orderby` に合わせて正しいものを入れなおす物らしい。

```php:wp-includes/user.php
//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` の場合の処理を入れたら動きそうだ。


```php:wp-includes/user.php
//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;
	}
```

こんな感じかな。

## 一応ちゃんと動いた

ここまで行うと、なんとか想定通りにうごいてくれた。
とはいえコアを弄ってしまっている上に、かなり手探りだったのでちょっと怪しいところ。

## 最後に

### これからの目標
- コアを弄らずに同じ動作を実装したい
- ユーザー登録/編集でフリガナを変更できる様にしたい

という訳で、まだまだ手探りなストックにはなりますが、
忌憚の無いご意見や、アドバイスなどお聞きできれば有難いです。
引き続き勉強して、何か気がついた所があれば追記・編集していきます。