2018年6月28日更新
以下のコードはほとんど問題なく動作しますが、WP> = 4.6.0(PHP 7を使用)のコードを書き直します。
function add_course_section_filter( $which ) {
    // create sprintf templates for <select> and <option>s
    $st = '<select name="course_section_%s" style="float:none;"><option value="">%s</option>%s</select>';
    $ot = '<option value="%s" %s>Section %s</option>';
    // determine which filter button was clicked, if any and set section
    $button = key( array_filter( $_GET, function($v) { return __( 'Filter' ) === $v; } ) );
    $section = $_GET[ 'course_section_' . $button ] ?? -1;
    // generate <option> and <select> code
    $options = implode( '', array_map( function($i) use ( $ot, $section ) {
        return sprintf( $ot, $i, selected( $i, $section, false ), $i );
    }, range( 1, 3 ) ));
    $select = sprintf( $st, $which, __( 'Course Section...' ), $options );
    // output <select> and submit button
    echo $select;
    submit_button(__( 'Filter' ), null, $which, false);
}
add_action('restrict_manage_users', 'add_course_section_filter');
function filter_users_by_course_section($query)
{
    global $pagenow;
    if (is_admin() && 'users.php' == $pagenow) {
        $button = key( array_filter( $_GET, function($v) { return __( 'Filter' ) === $v; } ) );
        if ($section = $_GET[ 'course_section_' . $button ]) {
            $meta_query = [['key' => 'courses','value' => $section, 'compare' => 'LIKE']];
            $query->set('meta_key', 'courses');
            $query->set('meta_query', $meta_query);
        }
    }
}
add_filter('pre_get_users', 'filter_users_by_course_section');
私は、@ birgireと@cale_bからいくつかのアイデアを取り入れました。具体的には、私は:
- $which追加された変数を使用- v4.6.0
- 翻訳可能な文字列を使用してi18nのベストプラクティスを使用。 __( 'Filter' )
- 交換用のループ(よりファッショナブルな?) array_map()、array_filter()と、range()
- sprintf()マークアップテンプレートの生成に使用
- 代わりに角括弧配列表記を使用 array()
最後に、以前の解決策でバグを発見しました。これらのソリューションは常に<select>BOTTOMよりもTOP を優先し<select>ます。したがって、上部のドロップダウンからフィルターオプションを選択し、その後下部のドロップダウンからフィルターオプションを選択した場合、フィルターは(上部にある場合は)上部の値のみを使用します(空白でない場合)。この新しいバージョンはそのバグを修正します。
更新2018-02-14
この問題はWP 4.6.0以降パッチされており、変更は公式ドキュメントに記載されています。ただし、以下の解決策はまだ機能します。
問題の原因(WP <4.6.0)
問題は、restrict_manage_usersアクションが2回呼び出されることでした。1回はユーザーテーブルの上、1回はその下です。つまり、2つのselectドロップダウンが同じ名前で作成されます。ときにFilterボタンをクリックすると、どのような値は秒であるselect(すなわち、以下の表1)は、すなわちテーブル上記のもの、最初のものの値を上書き要素。
WPソースに飛び込む場合、restrict_manage_usersアクションは内からトリガーされますWP_Users_List_Table::extra_tablenav($which)。これは、ユーザーのロールを変更するためのネイティブドロップダウンを作成する関数です。この関数は、フォームの上または下のどちらを$which作成してselectいるかを示す変数を利用して、2つのドロップダウンに異なるname属性を与えることができます。残念ながら、$which変数はrestrict_manage_usersアクションに渡されないため、独自のカスタム要素を区別する別の方法を考え出す必要があります。
@Linneaが示唆するように、これを行う1つの方法は、JavaScriptを追加してFilterクリックをキャッチし、2つのドロップダウンの値を同期させることです。ここで説明するPHPのみのソリューションを選択しました。
それを修正する方法
HTML入力を値の配列に変換する機能を利用して、未定義の値を取り除くために配列をフィルタリングできます。これがコードです:
    function add_course_section_filter() {
        if ( isset( $_GET[ 'course_section' ]) ) {
            $section = $_GET[ 'course_section' ];
            $section = !empty( $section[ 0 ] ) ? $section[ 0 ] : $section[ 1 ];
        } else {
            $section = -1;
        }
        echo ' <select name="course_section[]" style="float:none;"><option value="">Course Section...</option>';
        for ( $i = 1; $i <= 3; ++$i ) {
            $selected = $i == $section ? ' selected="selected"' : '';
            echo '<option value="' . $i . '"' . $selected . '>Section ' . $i . '</option>';
        }
        echo '</select>';
        echo '<input type="submit" class="button" value="Filter">';
    }
    add_action( 'restrict_manage_users', 'add_course_section_filter' );
    function filter_users_by_course_section( $query ) {
        global $pagenow;
        if ( is_admin() && 
             'users.php' == $pagenow && 
             isset( $_GET[ 'course_section' ] ) && 
             is_array( $_GET[ 'course_section' ] )
            ) {
            $section = $_GET[ 'course_section' ];
            $section = !empty( $section[ 0 ] ) ? $section[ 0 ] : $section[ 1 ];
            $meta_query = array(
                array(
                    'key' => 'course_section',
                    'value' => $section
                )
            );
            $query->set( 'meta_key', 'course_section' );
            $query->set( 'meta_query', $meta_query );
        }
    }
    add_filter( 'pre_get_users', 'filter_users_by_course_section' );
ボーナス:PHP 7リファクタリング
私がPHP 7に興奮しているので、PHP 7サーバーでWPを実行している場合に備えて、null合体演算子??を使用したより短くてセクシーなバージョンを次に示します。
function add_course_section_filter() {
    $section = $_GET[ 'course_section' ][ 0 ] ?? $_GET[ 'course_section' ][ 1 ] ?? -1;
    echo ' <select name="course_section[]" style="float:none;"><option value="">Course Section...</option>';
    for ( $i = 1; $i <= 3; ++$i ) {
        $selected = $i == $section ? ' selected="selected"' : '';
        echo '<option value="' . $i . '"' . $selected . '>Section ' . $i . '</option>';
    }
    echo '</select>';
    echo '<input type="submit" class="button" value="Filter">';
}
add_action( 'restrict_manage_users', 'add_course_section_filter' );
function filter_users_by_course_section( $query ) {
    global $pagenow;
    if ( is_admin() && 'users.php' == $pagenow) {
        $section = $_GET[ 'course_section' ][ 0 ] ?? $_GET[ 'course_section' ][ 1 ] ?? null;
        if ( null !== $section ) {
            $meta_query = array(
                array(
                    'key' => 'course_section',
                    'value' => $section
                )
            );
            $query->set( 'meta_key', 'course_section' );
            $query->set( 'meta_query', $meta_query );
        }
    }
}
add_filter( 'pre_get_users', 'filter_users_by_course_section' );
楽しい!