2026年5月25日
2026年5月25日
WordPressのカスタム管理画面ページにTablesorterでソート機能を追加する方法
WordPressの管理画面に自作したページの表を、見出しクリックで並べ替えられるようにするには、jQueryプラグインのTablesorterを自分のプラグイン内に同梱し、admin_enqueue_scripts でそのページにだけ読み込むのが手早い方法です。この記事では、管理メニューへのページ追加、表の出力(権限チェックとエスケープ込み)、Tablesorterの読み込みと初期化、数値や日付を正しく並べる工夫、データが多い場合の判断基準までを順に説明します。
なお、ここで扱うのはブラウザ側で並べ替える方式です。数千件を超えるデータや、ページ送りと組み合わせた並べ替えが必要なら、サーバー側で並べ替える WP_List_Table のほうが向いています。どちらを選ぶかの目安は後半で触れます。
Tablesorterについて先に知っておくこと
Tablesorterは、<table> の見出しをクリックすると行を並べ替えるjQueryプラグインです。元のプロジェクトのほかに、機能を大きく拡張したフォーク版(GitHubの Mottie/tablesorter)が広く使われており、この記事でもフォーク版を前提にします。フォーク版は2.31系が長く最新版で、近年は大きな更新が少ない状態です(2026年10月現在)。jQueryの将来のメジャーバージョンでの動作は保証されていないので、導入前にリポジトリの更新状況とissueを確認し、管理画面内の限られた用途で使うことをおすすめします。
WordPressのコアにはTablesorterは同梱されていません。jQuery本体はコアに含まれているので、依存関係として jquery を指定すれば読み込まれます。
手順1:プラグインを用意してファイルを配置する
テーマの functions.php に書くとテーマを切り替えたときに管理画面のページごと消えるため、管理用の機能は小さな独自プラグインにまとめます。構成は次のようにします。
wp-content/plugins/my-admin-report/
├── my-admin-report.php
└── assets/
├── jquery.tablesorter.min.js (配布元から取得したファイル)
└── admin-report.js
Tablesorterのファイルは外部CDNから直接読み込むこともできますが、管理画面で使うスクリプトは自サーバーに置くほうが、CDNの障害や改ざんの影響を受けません。取得したバージョン番号は控えておき、後で wp_register_script() のバージョン引数に使います。
手順2:管理ページと表を出力する
add_menu_page() は戻り値としてそのページの「フックサフィックス」を返します。これを変数に保存しておき、スクリプトの読み込み先を絞るのに使います。admin_menu は admin_enqueue_scripts より先に実行されるので、この順番で値を受け渡せます。
<?php
/**
* Plugin Name: My Admin Report
* Description: 投稿の一覧をソート可能な表で表示する管理ページ
*/
defined( 'ABSPATH' ) || exit;
add_action( 'admin_menu', function () {
$hook = add_menu_page(
'投稿レポート',
'投稿レポート',
'edit_others_posts', // このページを見られる権限
'my-admin-report',
'my_admin_report_render',
'dashicons-list-view',
30
);
$GLOBALS['my_admin_report_hook'] = $hook; // admin_enqueue_scripts で比較に使う
} );
function my_admin_report_render() {
if ( ! current_user_can( 'edit_others_posts' ) ) {
wp_die( esc_html__( 'このページを表示する権限がありません。' ) );
}
$posts = get_posts( array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => 300,
'orderby' => 'date',
'order' => 'DESC',
) );
?>
<div class="wrap">
<h1>投稿レポート</h1>
<table id="my-report-table" class="widefat striped">
<thead>
<tr>
<th>タイトル</th>
<th>投稿者</th>
<th>コメント数</th>
<th>公開日</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php foreach ( $posts as $p ) : ?>
<tr>
<td><?php echo esc_html( get_the_title( $p ) ); ?></td>
<td><?php echo esc_html( get_the_author_meta( 'display_name', $p->post_author ) ); ?></td>
<td data-text="<?php echo esc_attr( (int) $p->comment_count ); ?>">
<?php echo esc_html( number_format_i18n( $p->comment_count ) ); ?>
</td>
<td data-text="<?php echo esc_attr( get_post_time( 'U', true, $p ) ); ?>">
<?php echo esc_html( get_the_date( '', $p ) ); ?>
</td>
<td><a href="<?php echo esc_url( get_edit_post_link( $p ) ); ?>">編集</a></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php
}
ポイントは3つです。1つ目は、Tablesorterが <thead> と <tbody> を前提に動くことです。見出し行を <tbody> に入れると、見出しまで並べ替えの対象になります。2つ目は、class="widefat striped" を付けるとWordPress標準の表デザインになり、管理画面になじむことです。3つ目は、メニュー登録時の権限指定に加えて、表示関数の中でも current_user_can() で確認し、出力はすべて esc_html()・esc_attr()・esc_url() でエスケープしていることです。
data-text 属性は、並べ替えに使う値を表示とは別に持たせるためのものです。コメント数は 1,234 のような区切り付き、日付はサイトの日付形式で表示されるため、そのままでは文字列として並んでしまうことがあります。フォーク版のTablesorterは既定で data-text 属性の値を並べ替えに使うので、数値やUNIXタイムスタンプを入れておくと正しい順になります。
手順3:対象ページだけにスクリプトを読み込む
add_action( 'admin_enqueue_scripts', function ( $hook_suffix ) {
if ( empty( $GLOBALS['my_admin_report_hook'] ) || $GLOBALS['my_admin_report_hook'] !== $hook_suffix ) {
return; // 他の管理画面では読み込まない
}
$base = plugin_dir_url( __FILE__ ) . 'assets/';
wp_register_script(
'jquery-tablesorter',
$base . 'jquery.tablesorter.min.js',
array( 'jquery' ),
'2.31.3', // 実際に同梱したバージョンに合わせる
array( 'in_footer' => true )
);
wp_enqueue_script(
'my-admin-report',
$base . 'admin-report.js',
array( 'jquery-tablesorter' ),
'1.0.0',
array( 'in_footer' => true )
);
wp_register_style( 'my-admin-report', false, array(), '1.0.0' );
wp_enqueue_style( 'my-admin-report' );
wp_add_inline_style( 'my-admin-report', '
#my-report-table thead th { cursor: pointer; }
#my-report-table .tablesorter-headerAsc::after { content: " \25B2"; }
#my-report-table .tablesorter-headerDesc::after { content: " \25BC"; }
' );
} );
すべての管理画面にスクリプトを読み込むと、他のプラグインの画面と衝突したり、管理画面全体が重くなったりします。フックサフィックスで絞るのはそのためです。サフィックスは toplevel_page_my-admin-report のような文字列になりますが、親メニューの種類によって変わるので、ハードコードせず add_menu_page() の戻り値を使うほうが安全です。
wp_register_script() の第5引数に配列(in_footer や strategy)を渡す形式はWordPress 6.3以降のものです。それより古い環境では true を渡します。
見出しの矢印に使っている tablesorter-headerAsc などのクラス名は、フォーク版が付与するものです。バージョンやテーマ設定で異なる場合があるので、ブラウザの開発者ツールで実際のクラス名を確認してから調整してください。
手順4:Tablesorterを初期化する
assets/admin-report.js に初期化処理を書きます。WordPressの管理画面ではjQueryがnoConflictモードで読み込まれるため、$ は使えません。jQuery(function ($) { ... }) の形で書くと、内側で $ を使えます。
jQuery(function ($) {
var $table = $('#my-report-table');
if (!$table.length || typeof $.fn.tablesorter !== 'function') {
return;
}
$table.tablesorter({
sortList: [[3, 1]], // 4列目(公開日)を降順で初期表示
headers: {
4: { sorter: false } // 5列目(操作)は並べ替えない
}
});
});
列の番号は0から数えます。sortList の [3, 1] は「4列目を降順」という意味で、0 なら昇順です。リンクだけの列のように並べ替える意味がない列は、headers で sorter: false を指定して対象から外します。
動かないときの確認ポイント
- スクリプトが読み込まれていない: ページのソースか開発者ツールのNetworkタブで、
jquery.tablesorter.min.jsが読み込まれているか確認します。読み込まれていなければ、フックサフィックスの比較が一致していない可能性が高いです。error_log( $hook_suffix );で実際の値を確認します。 - **
tablesorter is not a functionのエラー**: 依存関係の指定漏れで、初期化スクリプトがTablesorterより先に実行されています。wp_enqueue_script()の依存配列を確認します。 - 数値や日付の順序がおかしい: 表示用の文字列で並べ替えられています。
data-text属性に数値を入れ、HTMLに出力されているか確認します。 - 見出しまで並べ替わる: 見出し行が
<thead>の中にありません。
ブラウザ側ソートとWP_List_Tableの使い分け
Tablesorterは、表示済みのHTMLを並べ替えるだけなので、サーバーへの再問い合わせがなく反応が速いのが利点です。一方で、全件をHTMLとして出力する必要があるため、行数が増えるとページの読み込みが重くなります。目安として数百件程度まではTablesorterで十分ですが、それを超える場合や、検索・絞り込み・一括操作も必要な場合は、WordPress標準の投稿一覧と同じ仕組みの WP_List_Table を継承し、SQLの ORDER BY で並べ替えるほうが適しています。フォーク版には表の分割表示(pager)やフィルターのウィジェットもありますが、全件をブラウザに送る前提は変わりません。
ダッシュボードのウィジェット内の表に適用したい場合は、wp_add_dashboard_widget() で出力した表に同じ初期化を行い、admin_enqueue_scripts の比較対象をダッシュボードのフックサフィックスである index.php にします。
まとめ
- Tablesorterは独自プラグインに同梱し、
add_menu_page()の戻り値で対象ページだけに読み込む - 表は
<thead>・<tbody>で組み、権限チェックとエスケープを行って出力する - 数値や日付は
data-text属性に並べ替え用の値を持たせる - 管理画面では
jQuery(function ($) { ... })で初期化し、操作列などはsorter: falseで外す - データが多い・検索や一括操作も必要なら
WP_List_Tableを検討する