サイトアイコン Capital P

WordPress+Vue.JSで作るジョブボード(4)最終的に jQueryで完成する

さて、これまでの連載”Job Board with Vue.JS“を続けてきたのだが、前回からかなりの間が開いてしまったこと、そして、作成すべき機能(ジョブボード)の必要性の高まりに比してなかなか開発スピード&チュートリアル作成スピードが上がらないこと、それほどインタラクティブな要素がないということから、今回はjQueryで作成することになった。2018年の現時点においてもWeb制作現場で幾度となく繰り返されている光景だろうが、筆者もまた同じ光景を見せつけ、華麗にこの連載を終了する。

ジョブボードの作成

以前まではちまちまとダッシュボードを作成していたが、よく考えたらWordPressにはダッシュボードを作成するための必須要素がほとんど揃っている。そのため、カスタムなんちゃらを利用し、次のような機能を作成した。

Capital Pの新しいジョブボード
カスタム投稿タイプ、カスタムタクソノミー、カスタムフィールドを駆使して次のような編集画面を作成。

ポイントは下記の通り。

これらの機能を実装するまでにしたことをざっくり説明する。

申し込みの定義

さて、ある特定の投稿タイプ(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投稿タイプが一つ作成されるということだ。

それでは、次のようなフローでボタンを押させるようにしよう。

ボタンの表示は割愛するが、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もどちらも優れたフレームワークであり、その用途さえ間違えなければ有用ということは申し添えておきたい。

有料会員向け特典

以下は有料会員専用の特典として次のものをお届けする。

実際の作業量としては、Vue以外が大半を占めていることからもわかっていただけると思う。

この投稿の続きを読むためには、Capital Pでログインする必要があります。

続きを読む
モバイルバージョンを終了