
wordpressには直接管理画面にアクセスしなくても記事を新規投稿・編集することができます。 自分で投稿用に完全オリジナル管理画面を制作したり、CSVやJSONなどのファイルを利用して一括で更新することが可能になります。
wp_insert_post( $post, $wp_error )を利用
worpdressの関数、wp_insert_postは引数を設定することで直接データベースに記事投稿や修正をすることができます。 関数リファレンス/wp insert post
$postに以下の引数を配列で設定することができます。
$my_post = array(
'ID' => [ <投稿 ID> ] // 既存の投稿を更新する場合に指定。
'post_content' => [ <文字列> ] // 投稿の全文。
'post_name' => [ <文字列> ] // 投稿のスラッグ。
'post_title' => [ <文字列> ] // 投稿のタイトル。
'post_type' => [ 'post' | 'page' | 'link' | 'nav_menu_item' | カスタム投稿タイプ ] // 投稿タイプ。デフォルトは 'post'。
'post_category' => [ array(<カテゴリー ID>, ...) ] // 投稿カテゴリー。デフォルトは空(カテゴリーなし)。
'tags_input' => [ 'tag, tag, ...' | array ] // 投稿タグ。デフォルトは空(タグなし)。
);
wp_insert_post( $my_post, $wp_error );
post_title と post_contentは必須です。
$wp_errorはtrueにするとinsertに失敗したときのErrorオブジェクトを返すか返さないかの設定で、未設定の場合は0が返ってきます。未設定にしておいて問題ないでしょう。
独自の入力フォームからPOSTデータを利用してみる
入力フォームの設定。
<form action="[送信するURL]" method="POST">
[入力フィールドの設定]
<button type="submit">送信する</button>
</form>
nonceフィールドで認証の設定
フォームで入力したデータは正しく送信されたデータかチェックする必要があります。そのためのnonceフィールドを設定します。
<form action="[送信するURL]" method="POST">
<?php wp_nonce_field('outside_postform', 'nonce_outside_postform'); ?>
[入力フィールドの設定]
<button type="submit">送信する</button>
</form>
通常のPHPだとcsrfの対策のため、ワンタイムトークンを生成してセッションとPOSTデータの一致を調べたり、リファラーを確認したりする必要がありますが、wordpressではwp_nonce_field()の関数を使うことでそのへんの処理を全部やってくれます。
設定したnonceフィールドのデータチェックします。チェエクにはwp_verify_nonce()を利用します。
$_POSTを直接wp_insert_postの引数に設定するのは気が引けるが、wp_insert_postには最初から無害化の処理がされるので、XSS(クロスサイト・スクリプティング)の対策は行う必要はありません。
wp_insert_post();実行後にリダイレクト
wp_insert_post();はインサートが完了しても、そのデータは消えません。POSTする場所は同一ページを利用しているため、リロードをしてしまうと重複して投稿されてしまう。
重複投稿を避けるためwp_insert_post()は現在のページにもう一度リダイレクトさせます。リダイレクトさせるURLに投稿が完了ステータスを付与してアラートで表示させます。
//インサートの実行
public function run_insert_post()
{
if (is_user_logged_in()) {
$nonce = $this->post_data['nonce_outside_postform'];
if (wp_verify_nonce($nonce, 'outside_postform')) {
$my_post = array(
'post_status' => 'publish',
'post_title' => $_POST['post_title'],
'post_name' => $_POST['post_name'],
'post_type' => $_POST['post_type'],
'post_content' => $_POST['post_content'],
'post_category' => $_POST['category'],
'tags_input' => $this->insert_post_tag()
);
//IDがある場合投稿の編集
if (isset($_POST['ID']) && get_post($_POST['ID'])) {
$my_post['ID'] = $_POST['ID'];
}
$insert_status = wp_insert_post($my_post);
if ($insert_status) {
$mesg = '投稿完了';
} else {
$mesg = '投稿失敗';
}
} else {
$mesg = '不正な投稿';
}
global $post;
$this->this_post = $post;
$url = add_query_arg(array('outside_postform_func_status' => $mesg), get_the_permalink($this->this_post->ID));
wp_redirect($url);
exit;
}
}
ステータスからアラートを実行させてから元のページに遷移して完了となります。
//アラート後にページの遷移
public function run_alert()
{
$link = get_the_permalink($this->this_post->ID);
$insert_status = urldecode($this->get_data['outside_postform_func_status']);
print <<< EOT
<script>
alert("{$insert_status}");
location.href = "{$link}";
</script>
EOT;
}
wp_insert_post()を使ったプラグインを制作
今までの内容を使ってプラグインを作ってみます。
プラグインにするための仕様をまとめてclass化
- ショートコードを使ってどこのページでも外部投稿フォームを作れるようにする。
- 現在のページにPOSTしてwp_insert_post()を動かす
- 投稿結果のステータスをアラートで表示
プラグイン化する場合、実行タイミングよっては関数が動かない場合があります。actionフックの内容を確認して、適切なタイミングで実行させればエラーは起こりません。
public function __construct()
{
$this->plugin_path = WP_PLUGIN_URL.'/'.str_replace(basename(__FILE__), "", plugin_basename(__FILE__));
add_shortcode('outside_postform', array($this, 'outside_postform_func'));
add_action('wp_enqueue_scripts', array($this, 'theme_name_scripts'));
//POSTデータの取得
$args = array(
'nonce_outside_postform' => FILTER_SANITIZE_ENCODED
);
$this->post_data = filter_input_array(INPUT_POST, $args);
if ($this->post_data['nonce_outside_postform']) {
add_action('get_header', array($this, 'run_insert_post'));
}
//GETデータ取得
$args = array(
'outside_postform_func_status' => FILTER_SANITIZE_ENCODED
);
$this->get_data = filter_input_array(INPUT_GET, $args);
if ($this->get_data['outside_postform_func_status']) {
add_action('wp_head', array($this, 'run_alert'));
}
}
ページのリロードでPOSTデータを連続投稿しないために、wp_insert_post()の後はリダイレクトをさせます。リダイレクトはget_headerのactionフックを利用することで。htmlより先にリダイレクトを実行できます。
投稿結果のステータスを表示させるアラートはjsを利用するため、wp_headのactionフックを利用します。そして、アラート表示後のパラメーターを最終的に取り除くためlocation.hrefでページを遷移させています。
<?php
/*
Plugin Name: Outeside Postform
Plugin URI:
Description: 外部フォームから投稿を可能にするプラグイン
Version: 1.0
Author: MATSUI KAZUKI
Author URI:
License:
*/
$outside_postform = new OutsidePostform();
class OutsidePostform
{
private $plugin_path;
private $post_data;
private $get_data;
private $this_post;
public function __construct()
{
$this->plugin_path = WP_PLUGIN_URL.'/'.str_replace(basename(__FILE__), "", plugin_basename(__FILE__));
add_shortcode('outside_postform', array($this, 'outside_postform_func'));
add_action('wp_enqueue_scripts', array($this, 'theme_name_scripts'));
add_filter( 'upload_mimes', array($this, 'custom_mime_types') );
//POSTデータの取得
$args = array(
'nonce_outside_postform' => FILTER_SANITIZE_ENCODED
);
$this->post_data = filter_input_array(INPUT_POST, $args);
if ($this->post_data['nonce_outside_postform']) {
add_action('get_header', array($this, 'run_insert_post'));
}
//GETデータ取得
$args = array(
'outside_postform_func_status' => FILTER_SANITIZE_ENCODED
);
$this->get_data = filter_input_array(INPUT_GET, $args);
if ($this->get_data['outside_postform_func_status']) {
add_action('wp_head', array($this, 'run_alert'));
}
}
//csvを許可
public function custom_mime_types( $mimes ) {
$mimes['csv'] = 'text/csv';
return $mimes;
}
//ショートコード
public function outside_postform_func()
{
$form = '';
if (is_user_logged_in()) {
$nonce = wp_nonce_field('outside_postform', 'nonce_outside_postform', true, false);
$action_url = $_SERVER['REQUEST_URI'];
//投稿タイプ
$select_option = '';
$args = array(
'public' => true,
);
$post_types = get_post_types($args, 'names');
unset($post_types['attachment']);
foreach ($post_types as $v) {
$select_option .= '<option>' . $v . '</option>';
}
unset($v);
//カテゴリー、タグ
$cats_li = $this->get_post_category_terms('category');
$tags_li = $this->get_post_category_terms('post_tag');
//formタグ
$form = <<< EOT
<form id="outside_postform_func" action="{$action_url}" method="POST">
{$nonce}
<input type="number" name="ID" value="" placeholder="ID"><span class="sub">※修正の場合はIDを入力する</span>
<input type="text" name="post_title" value="" placeholder="ここにタイトルを入力">
<input type="text" name="post_name" value="" placeholder="スラッグ">
<span class="heading">投稿タイプ</span>
<select name="post_type">{$select_option}</select>
<span class="heading">カテゴリー</span>
{$cats_li}
<span class="heading">タグ</span>
{$tags_li}
<textarea name="post_content"></textarea>
<button class="button button-large button-primary" type="submit">送信する</button>
</form>
EOT;
}
return $form;
}
//termsのリスト取得
private function get_post_category_terms($taxonomies)
{
$checkbox_li = '<ul class="terms_li">';
$args = array(
'hide_empty' => false,
);
$cats = get_terms($taxonomies, $args);
foreach ($cats as $v) {
$checkbox_li .= <<< EOT
<li>
<label><input type="checkbox" name="{$taxonomies}[]" value="{$v->term_id}">{$v->name}</label>
</li>
EOT;
}
unset($v);
$checkbox_li .= '</ul>';
return $checkbox_li;
}
//外部ファイル読み込み
public function theme_name_scripts()
{
wp_enqueue_style('style-name', $this->plugin_path . 'assets/css/style.css');
}
//インサートの実行
public function run_insert_post()
{
if (is_user_logged_in()) {
$nonce = $this->post_data['nonce_outside_postform'];
if (wp_verify_nonce($nonce, 'outside_postform')) {
$my_post = array(
'post_status' => 'publish',
'post_title' => $_POST['post_title'],
'post_name' => $_POST['post_name'],
'post_type' => $_POST['post_type'],
'post_content' => $_POST['post_content'],
'post_category' => $_POST['category'],
'tags_input' => $this->insert_post_tag()
);
//IDがある場合投稿の編集
if (isset($_POST['ID']) && get_post($_POST['ID'])) {
$my_post['ID'] = $_POST['ID'];
}
$insert_status = wp_insert_post($my_post);
if ($insert_status) {
$mesg = '投稿完了';
} else {
$mesg = '投稿失敗';
}
} else {
$mesg = '不正な投稿';
}
global $post;
$this->this_post = $post;
$url = add_query_arg(array('outside_postform_func_status' => $mesg), get_the_permalink($this->this_post->ID));
wp_redirect($url);
exit;
}
}
//タグの配列を文字列に変更
private function insert_post_tag() {
$tag_array = array();
if(is_array($_POST['post_tag'])){
foreach($_POST['post_tag'] as $v) {
$tag_data = get_tag($v);
$tag_array[] = $tag_data->name;
}
unset($v);
}
return implode(",", $tag_array);
}
//アラート後にページの遷移
public function run_alert()
{
$link = get_the_permalink($this->this_post->ID);
$insert_status = urldecode($this->get_data['outside_postform_func_status']);
print <<< EOT
<script>
alert("{$insert_status}");
location.href = "{$link}";
</script>
EOT;
}
}
ショートコードを貼り付ければフォームが表示されます。