WordPressでサイト上(フロント側)に投稿機能を独自実装する方法
こんにちは、Webエンジニアのゾノ( @ozonosho )です。
今回の記事ではWordPressでサイト上(フロント側)にユーザーが自由に投稿できる機能を独自に実装する方法を紹介します。
たとえば掲示板のように不特定多数のユーザーが投稿するサービスを作る場合、サイト上に投稿フォームを設けてユーザーが自由に投稿できる仕組みが必要です。WordPressに備わっている投稿機能は管理画面内のみなので、サイト上に投稿機能を作る場合にはプラグインを利用するか独自に実装する必要があります。
プラグインだと出来ることに限界があるため、柔軟な投稿機能(例:画像を投稿する、投稿時に投稿内容に応じて自動でタグやタームを割り当てる、など)を実現したい場合には独自に実装するほうが良いでしょう。
そんなわけで、僕の運営するいくつかのサイトでは独自に投稿機能を実装しています。
▽実装例(未来地図HPのフリースクール情報投稿フォーム)
実際にはもっと多数の項目を登録できるようにしており、投稿した内容は下記の詳細表示ページに掲載されます。
▽実際のフリースクール詳細ページ(例)
https://miraitizu.com/freeschool/27983
投稿フォームを自作で用意すればタクソノミーやカテゴリーも自由に紐づけることができるので、フリースクール一覧ページにあるような柔軟な検索機能も実現できます。
サイト上に投稿機能を実装する方法
今回は下記のような簡易仕様の実装例をご紹介します。
- 今回紹介する投稿機能の仕様
-
- 会員制の掲示板で、会員登録したユーザーのみがトピック(投稿タイプ:topic)を投稿できる
- トピックにはタイトル(wp_posts:post_title)と本文(wp_posts:post_content)を登録できる
- トピックにはカテゴリー(カスタムタクソノミー:topic_cat)を登録できる
- トピックには備考(カスタムフィールド:topic_other)を登録できる
投稿機能の実装は大きく分けて下記の3段階になります。
- 投稿フォームの用意
- 投稿内容の登録処理
- 投稿表示ページの用意
①投稿フォームの用意
まずはユーザーがトピックを投稿するための投稿フォームを用意してみます。
<!-- role「user」の権限を持つユーザーだけにフォームを表示 -->
<?php if(current_user_can('user')) { ?>
<form method="post">
<label for="post_title">タイトル</label>
<input id="post_title" maxlength="50" name="post_title" type="text" placeholder="最大50文字" required>
<label for="post_content">本文</label>
<textarea id="post_content" maxlength="3000" name="post_content" placeholder="最大3,000文字" required></textarea>
<?php
//タクソノミー「topic_cat」のターム一覧を取得
$topic_cats = get_terms('topic_cat', array('hide_empty' => 0));
?>
<?php if($topic_cats) { ?>
<label for="topic_cat">カテゴリー</label>
<select id="topic_cat">
<?php foreach($topic_cats as $topic_cat) { ?>
<option value="<?php echo $topic_cat->term_id; ?>"><?php echo $topic_cat->name; ?></option>
<?php } ?>
</select>
<?php } ?>
<label for="topic_other">備考</label>
<textarea id="topic_other" maxlength="1000" name="topic_other" placeholder="1000文字以内"></textarea>
<input name="action" type="hidden" value="do_post_topic">
<?php wp_nonce_field('do_post_topic', 'token'); ?>
<button type="submit">投稿する</button>
</form>
<?php } ?>
こんな感じでしょうか。
※この記事を書くためにベタ書きで書いたので動作しなかったらすみません…w
仕様に記載したとおり「タイトル」「本文」「カテゴリー」「備考」の4項目を投稿できるようにしています。
あとはCSRF対策用にwp_nonce_fieldでトークンを発行しています。
②投稿内容の登録処理
投稿ボタンが押された後は、送信情報や実行者の権限について検証したうえで問題なければ登録処理をおこないます。
WordPressの場合はinitやwpといったフックが用意されているので、適切なタイミングで処理を挟みましょう。
functions.phpに記述する処理例を載せてみます。
<?php
add_action('wp', function() {
if(isset($_POST['action']) && $_POST['action'] === 'do_post_topic') {
do_post_topic();
}
});
function do_post_topic() {
//トークン認証
if(!isset($_POST['token']) || !wp_verify_nonce($_POST['token'], 'do_post_topic')) {
return false;
}
/*
①入力内容・権限のチェック
*/
$post_title = (isset($_POST['post_title'])) ? $_POST['post_title'] : '';
$post_content = (isset($_POST['post_content'])) ? $_POST['post_content'] : '';
$topic_cat = (isset($_POST['topic_cat'])) ? $_POST['topic_cat'] : '';
$topic_other = (isset($_POST['topic_other'])) ? $_POST['topic_other'] : '';
//必須項目チェック
if(!$post_title || !$post_content) {
return false;
}
//権限チェック:(例)roleに「user」が割り当てられているかユーザーかどうか
if(!current_user_can('user')) {
return false;
}
/*
②登録処理
*/
$args = array(
'post_type' => 'topic', //投稿タイプ
'post_title' => $post_title,
'post_content' => $post_content,
'post_author' => get_current_user_id(),
'post_status' => 'publish',
'tax_input' => array(
'topic_cat' => $topic_cat
),
'meta_input' => array(
'topic_other' => $topic_other
)
);
$post_id = wp_insert_post($args);
if(!$post_id) {
return false;
}
//投稿詳細ページにリダイレクト
wp_safe_redirect(get_the_permalink($post_id));
exit;
}
?>
①のとおり、まずは入力内容・権限のチェックをおこないます。
必須項目の漏れがないか、適切な権限を持つユーザーによる操作かどうか、などを検証します。
上記例ではエラー時にreturn falseだけしていますが、実際にはエラー内容ごとに適切なエラーメッセージを返してあげると親切です。
検証して問題なければ②のとおり登録処理をおこないます。
上記コード例のようにwp_insert_post関数を利用すれば投稿IDと投稿データを渡すだけで登録できます。tax_inputやmeta_inputを利用すればタームやカスタムフィールドの情報もまとめて登録できるし、関数内でSQLインジェクション対策もされているので楽チンです。
- tax_inputの注意点
-
ユーザーの権限設定によってはtax_inputによるターム登録ができないようです。たとえばWordPressデフォルトで用意されている「購読者」の権限だと登録できないという記事がいくつか見つかりました。
そんなときにはwp_set_object_terms関数を利用してタームの登録だけ分けておこなうことで対処可能です。
③投稿表示ページの用意
最後に、登録した投稿内容を表示するためのページも用意してみます。
今回は投稿タイプ「topic」として登録したので、single.phpまたはsingle-topic.phpで表示する形になります。
登録データを表示させたい箇所に下記のようなコードを記述しましょう。
<?php
$post_id = get_the_ID();
$topic_cats = get_the_terms($post_id, 'topic_cat');
$topic_other = esc_attr(get_post_meta($post_id, 'topic_other', true));
?>
<h1><?php the_title(); ?></h1>
<?php if($topic_cats) { ?>
カテゴリー:<?php echo $topic_cats[0]->name; ?>
<?php } ?>
<h2>内容</h2>
<?php the_content(); ?>
<h2>備考</h2>
<?php echo nl2br($topic_other); ?>
(マークアップは適当なので気にしないでくださいw)
タイトルと本文はwp_postsテーブルに格納しているのでthe_title関数とthe_content関数でそれぞれ出力できます。
カテゴリーはget_the_terms関数を利用して投稿に紐づくタームを取得しましょう。
備考はカスタムフィールドに保存したのでget_post_meta関数を利用して取得しましょう。ユーザーが入力したタグやスクリプトを無効化したい場合は上記コードのようにesc_attr関数を利用するとエスケープされて便利です。
これで投稿の一連の流れが実装できました。
この記事では簡単な実装例のみ記載していますが、独自に投稿機能を実装すれば好きなタイミングに好きな処理を追加することができるので大変便利です。会員制サイトを制作する際にはぜひお試しください。
おわりに
以上、今回の記事ではWordPressでサイト上(フロント側)に投稿機能を独自実装する方法を紹介させていただきました。
当サイトではWordPressのカスタマイズ依頼を請け負っています。実現したい機能・要望がある方はぜひ下記ページよりご相談ください。