【WordPress】ダッシュボードのサイドバーにオリジナルのメニューを追加する

簡易的なスケジュール機能をワードプレスに作ろうと思って、新しくカスタム投稿タイプを設定していました。

用意したカスタムフィールドにある程度決まった内容を入力するだけですが、立ちふさがったのが日付の処理です。

投稿画面を開いた日を含む週だけで最初は実装してみようと思ってましたが、よくよく考えるとスケジュールを入力しておきたいのはその週だけではないです。

近いスケジュールの入力が多いとは言えそれだけではないですし。

なので、カスタムフィールドに値を渡すためのページを作ることにしました。

ダッシュボードのサイドバー

どこに作るかを最初に考えましたが。

ワードプレスを扱っていて、メニューを選ぶのに慣れているのはダッシュボードのサイドバーです。

プラグインを追加したり、カスタム投稿を追加したりすればサイドバー内に新しいメニューが表示されるので、新たにメニューを作成するならここです。

今回はカスタム投稿タイプ(一応、いつもどおりですが”test-post”としておきます。)を用意しているので、作成時点で投稿のメニューが表示されています。

そこに新規投稿ページにデフォルト値となる値を渡すためのメニューを追加します。

使用するのは、add_submenu_page()です。

add_submenu_page()

この関数の引数を設定することで、サブメニューが追加されます。

<?php
add_submenu_page(
  'edit.php?post_type=test-post',   //親メニューのスラッグ
  'スケジュール登録週選択',              //サブメニューページに表示するタイトル
  '週間スケジュール登録',               //サブメニューの表示名
  'manage_options',                 //表示される権限
  'before_edit_schedule',                      //サブメニューのスラッグ
  'before_edit_schedule',                      //ページの内容を表示するコールバック関数
  1                                                                   //メニュー内での表示位置
);
?>

第一引数で親メニューのスラッグを指定し、どのメニューのサブメニューなのかを決めます。

基本的なスラッグは調べれば出て来ますが。

実際のダッシュボードで、サブメニューを追加したいメニューにマウスカーソルをあわせるとブラウザの左下にリンク先のURLが表示されると思います。ブラウザの設定によるかもしれませんが。

このURLの「~/wp-admin/」に続く英字がここで使用するスラッグなので、基本スラッグを覚えなくても大丈夫です。

第二引数はサブメニューを開いた時に表示されるページタイトルを。

第三引数はサブメニューの表示名を。

第四引数でこのメニューを表示する権限を設定します。’manage_options’で管理者権限です。

第五引数でサブメニューを表示するページのスラッグを指定。

第六引数が、サブメニューの表示内容を設定するコールバック関数名を入力します。

第五引数と第六引数を同じ名前にしてますが、分けても大丈夫です。

第七引数はメニュー内での表示位置です。

こんな感じで、サブメニューの入れ物のようなものを作れるのが、add_submenu_page()です。

これをadmin_menuにフックして使います。

<?php
function add_schedule_submenu_page(){
    //スケジュール登録日付選択ページメニュー
    add_submenu_page( 'edit.php?post_type=test-post', 'スケジュール登録週選択', '週間スケジュール登録', 'manage_options', 'before_edit_schedule', 'before_edit_schedule', 1 );
}
add_action( 'admin_menu', 'add_schedule_submenu_page' );
?>

続いて、中身となるコールバック関数を作成していきます。

日付を渡すコールバック関数

本題では無いので、サラッと。

表示名の通り「週間スケジュール」で。予定を先に入れておき、変更があれば個別投稿で修正・・・という使い方を想定しています。

なので、サブメニューでしたいことは、「ページを開いた日から一番近い”次の”月曜日を取得して値を新規投稿ページに送信する」という感じです。

コードはこんな風に。

<?php
function before_edit_schedule(){
?>
    <div class="wrap">
        <h2>スケジュール登録週選択</h2>
        <form method="POST" action="<?php echo home_url() . '/wp-admin/post-new.php?post_type=test-post'; ?>">
        <?php
            //タイムゾーン設定
            date_default_timezone_set("Asia/Tokyo");
            //当日の日付を取得
            $today = new DateTime( );
            //一番近い未来の月曜日を取得
            $firstMonday = $today->modify( 'next Monday' );
            $firstMondays[] = $firstMonday->format( 'Y/m/d' );
            //一ヶ月分の月曜の日付を取得
            for( $i = 0; $i < 4; $i++ ){
                $firstMonday = $firstMonday->modify( 'next Monday' );
                //配列に入れる
                $firstMondays[] = $firstMonday->format( 'Y/m/d' );
            //ラジオボタンを表示
            }
            foreach( $firstMondays as $monday ){
        ?>
            <input type="radio" name="schedule-monday" value="<?php echo $monday; ?>"><?php echo $monday . "週"; ?><br/>
        <?php } ?>
            <input type="submit" value="スケジュール入力する">
        </form>
    </div>
<?php
    }
?>

新規投稿ページにわたすので、action属性のURLに’/wp-admin/post-new.php?post_type=test-post’を指定します。

後はDateTimeで直近の月曜日を取得し。

念のため5週分表示したいので配列にいれ、foreachでラジオボタンで表示。

という感じです。

あとはfunctions.phpで受け取った値をカスタムフィールドのデフォルト値に渡します。

<?php
//デフォルト値の設定
//設定日の取得
function from_new_schedule_form(){
    if( $_SERVER['REQUEST_METHOD'] == 'POST' && !empty( $_POST['schedule-monday'] ) ){
        $schedule_form_date = filter_input( INPUT_POST, "schedule-monday");
    }
    return $schedule_form_date;
}
//修正時の日付readonly
function set_readonly_schedule_date( $field ){
    $field['readonly'] = 1;
    return $field;
}
//デフォルト値:月曜
function new_schedule_monday( $field ){
    $schedule_date = new DateTime( from_new_schedule_form() );
        $field[ 'default_value' ] = $schedule_date->format( "Y/m/d" );
        $field[ 'readonly' ] = 1;
    return $field;
}
//値が渡されている場合と渡されていない場合で分岐
if( isset( $_POST['schedule-monday'] ) ){
    add_filter( 'acf/load_field/name=mon-day', 'new_schedule_monday' );
} else {
    add_filter( 'acf/load_field/name=mon-day', 'set_readonly_schedule_date' );
} 
//以下、曜日によってDateTimeをmodifyする。
?>

渡した値を変更されたくないので、readonlyを設定したところ。

新規投稿で値を渡した時のみの設定となってしまったので、修正時にもreadonlyが有効になるように調整しました。

あ、今回もカスタムフィールドはAdvanced Custom Fieldsでの作成なので、フックなどはそちらを使っています。

操作性を高める

今回はカスタム投稿タイプにサブメニューを追加する目的だったので、add_submenu_page()のみ使いましたが。

親メニューから作る場合は、add_menu_page()を使用します。

引数はほぼadd_submenu_page()と一緒なので、使いやすいのではないかと。

管理画面をカスタマイズできると、より管理が楽になりますね。