さて、これまでの連載”Job Board with Vue.JS“を続けてきたのだが、前回からかなりの間が開いてしまったこと、そして、作成すべき機能(ジョブボード)の必要性の高まりに比してなかなか開発スピード&チュートリアル作成スピードが上がらないこと、それほどインタラクティブな要素がないということから、今回はjQueryで作成することになった。2018年の現時点においてもWeb制作現場で幾度となく繰り返されている光景だろうが、筆者もまた同じ光景を見せつけ、華麗にこの連載を終了する。
「jQueryはオワコンではない」
「通常のウェブサイト制作をしないエンジニアがjQueryをディスってるだけ」
「jQueryはオワコンではない」
このスライド全コーダーに届いて欲しい#scc #サッポロクリエイティブキャンプ pic.twitter.com/pEpnJFTYEl— CSS設計完全ガイドの人 / Adobe XD UG札幌代表 / HubSpot CMS Ninja (@assialiholic) June 23, 2018
ジョブボードの作成
以前まではちまちまとダッシュボードを作成していたが、よく考えたらWordPressにはダッシュボードを作成するための必須要素がほとんど揃っている。そのため、カスタムなんちゃらを利用し、次のような機能を作成した。
ポイントは下記の通り。
- Captal Pの有料会員(寄稿者権限)はジョブボードの求人票を作成することができる採用者である。ただし、管理者によるレビューを経なければ公開することはできない。
- ログインし、「申し込み先を見る」というボタンを押さなければユーザーは求人表を見ることができない。
これらの機能を実装するまでにしたことをざっくり説明する。
申し込みの定義
さて、ある特定の投稿タイプ(job
)に対して申し込みをしたかどうかをどのように定義するかだが、今回は次のようなルールにしたがった。
- 申し込みは
submission
という投稿タイプにする。 submission
は親IDにjob
の投稿IDを持ち、カスタムフィールド(_job_submitter
)に申込者のユーザーIDを持つ- 一つの
job
に対して一人のユーザーが複数の申し込みを行うことはできない
これらのルールを徹底するには、まずカスタム投稿タイプが新規登録できないようにしておく必要がある。この場合、緊急避難的な意味で、「管理者は管理画面から新規登録できるけれども、採用者はできない」というルールを貸しておくのがよいだろう。「新規投稿できなくする」というのはわりと使い勝手の良い方法なので、WordPress の新規追加の権限を切り分けてみるなどを参考にぜひ採用されたし。
<?php // jobに紐づく投稿タイプsubmissionを作成 add_action( 'init', function(){ $args = [ 'label' => '申し込み', 'public' => false, 'show_ui' => true, 'capability_type' => 'post', 'show_in_menu' => 'edit.php?post_type=job', ]; if ( ! current_user_can( 'manage_options' ) ) { $args['capabilities'] = [ 'create_posts' => 'create_submissions', ]; } register_post_type( 'submission', $args ); } );
これで、目的とする投稿タイプが作成された。show_in_menu
は管理画面で投稿タイプ一覧を他の投稿タイプのメニューの下にぶらさげるときに使える。
関数の作成
あとは2つの関数を作成しよう。
まずは、ユーザーの申し込みを作成する関数。これは成功すればsubmission
の投稿オブジェクトを、失敗すればnull
オブジェクトを返すようにする。
/** * Detect if user has submitted to the job. * * @param null|int|WP_Post $post * @param int $user_id * @return WP_Post|null */ function capitalp_get_submission( $post = null, $user_id = 0 ) { $post = get_post( $post ); if ( ! $user_id ) { $user_id = get_current_user_id(); } foreach ( get_posts( [ 'post_type' => 'submission', 'post_parent' => $post->ID, 'author' => $post->post_author, 'posts_per_page' => 1, 'meta_query' => [ [ 'key' => '_job_submitter', 'value' => $user_id, ], ], ] ) as $submission ) { return $submission; } return null; }
申し込みを作成する関数は、上記の関数 capitalp_get_submission
を利用し、すでに申し込みが存在しているならばそれを利用し、なければ作成する。
/** * Submit to job * * @param null|int|WP_Post $post * @param int $user_id * @return WP_Post|WP_Error */ function capitalp_submit_job( $post = null, $user_id = 0 ) { $post = get_post( $post ); // Check existing. $submission = capitalp_get_submission( $post, $user_id ); if ( $submission ) { return $submission; } // Create new one. $submission_id = wp_insert_post( [ 'post_type' => 'submission', 'post_parent' => $post->ID, 'post_author' => $post->post_author, 'post_status' => 'publish', 'post_title' => sprintf( '%s - %s', get_the_title( $post ), date_i18n( 'Y-m-d H:i:s' ) ), ], true ); if ( is_wp_error( $submission_id ) ) { return $submission_id; } else { update_post_meta( $submission_id, '_job_submitter', $user_id ); return get_post( $submission_id ); } }
ではこれをどこで実行するか。この場合は以前紹介したREST APIを利用する。
/** * Register job board endpoint */ add_action( 'rest_api_init', function() { register_rest_route( 'capitalp/v1', 'job/(?P<job_id>\d+)', [ [ 'methods' => 'POST', 'args' => [ 'job_id' => [ 'required' => true, 'validate_callback' => function( $var ) { return 'job' === get_post_type( $var ); }, ], ], 'permission_callback' => function() { return current_user_can( 'read' ); }, 'callback' => function( WP_REST_Request $request ) { $job = get_post( $request->get_param( 'job_id' ) ); if ( 'publish' !== $job->post_status || ! capitalp_job_is_open( $job ) ) { return new WP_Error( 'job_is_closed', 'この求人は現在募集をしていません。', [ 'status' => 403, 'response' => 403, ] ); } $response = capitalp_submit_job( $job, get_current_user_id() ); return is_wp_error( $response ) ? $response : new WP_REST_Response( $response ); }, ], ] ); } );
/wp-json/capitalp/v1/job/10
にPOSTすると、そのユーザー専用のsubmission
投稿タイプが一つ作成されるということだ。
それでは、次のようなフローでボタンを押させるようにしよう。
- ユーザーは求人情報の詳細を見る。企業情報、申し込み先などはログインしないと見ることができない。
- ログインしたユーザーは求人に応募するつもりになったら、ボタンをクリックする。
submission
投稿オブジェクトがREST API経由で作成され、ユーザーは同じページにリダイレクト。晴れて求人に応募することができるようになる。
ボタンの表示は割愛するが、Javascriptはおさらいをかねて、読み込み方法を書いておこう。
// Enqueue Javascript. wp_enqueue_script( 'capitalp-job-board', get_stylesheet_directory_uri() . '/assets/js/job-board.js', [ 'jquery' ], wp_get_theme()->get( 'Version' ), true ); // Register variables. wp_localize_script( 'capitalp-job-board', 'JobBoard', [ 'endpoint' => rest_url( '/capitalp/v1/job/' . get_the_ID() ), 'nonce' => wp_create_nonce( 'wp_rest' ), ] );
ポイントは wp_localize_script
を利用して必要な変数(URL, nonceなど)を渡すこと。もちろん、ボタン自体に変数を持たせる(e.g. data-post-id="10"
)なら、もっと柔軟なパーツを作成することができる。
それでは、このJavascriptの中身を紹介しよう。申し込み完了後、おしゃれなインタラクションを行いつつ画面がそのまま書き変わるのが理想だが、時間がないこと、筆者にUXの才能がないことの2点の理由により、alert
を出してリロード、以上。
(function ($) { 'use strict'; $(document).on('click','#capitalp-job-submit-button', function(e){ e.preventDefault(); var $btn = $(this); if ( $(this).hasClass('disabled') ) { return; } $(this).attr('disabled', true).addClass('disabled'); $.post(JobBoard.endpoint, { _wpnonce: JobBoard.nonce }).done(function(response){ alert('求人情報の申し込み先を表示いたします。画面をリロードしますので、"OK"を押してください。'); window.location.reload(); }).fail(function(response){ var msg = '申し込みに失敗しました。またあとでやり直してください。'; if ( response.responseJSON && response.responseJSON.message ) { msg = response.responseJSON.message; } alert( msg ); }).always(function(){ $btn.removeClass('disabled').attr('disabled', null); }); }); })(jQuery);
最終的に、このようなページになる。
以上、簡単ではあるが、ジョブボード作成の連載を終えることにする。筆者は筆者でVueJSを利用しているのだが、どうも「ジョブボード」程度の要件だとわざわざVueJSを利用するまでもないようだ。もう少し、ユーザーのインタラクティブな動作が多い案件の方が適しているように思われる。
Vue.JSの連載として始まったものが最後jQueryで終わるとなると、Vue好きの人には「ふざけんな!」と声を荒げる向きもあるかもしれないが、どうかご寛恕いただきたい。時間がなかったのだ。VueもjQeuryもどちらも優れたフレームワークであり、その用途さえ間違えなければ有用ということは申し添えておきたい。
有料会員向け特典
以下は有料会員専用の特典として次のものをお届けする。
- 1時間20分程度のライブコーディングビデオ
- Github上での具体的なコミットの指摘(e.g. このコミットがカスタムナンチャラ、このコミットがREST API)
実際の作業量としては、Vue以外が大半を占めていることからもわかっていただけると思う。