【wordpressカスタマイズ】自作フォームから記事を投稿!wp_insert_post()の使い方

今回のテーマはwordpressの管理画面を利用せずに、自作の入力フォームを使って誰でも記事をが投稿できるようにするという内容を解説していきます。

wordpressにはinsert系の関数が複数用意されているので、割と簡単にデータベースに値を入れていくことがきるのです。

まずは今回作成するものの仕様確認

シングルページアプリケーションとして、自作の入力フォームを使ってwordpressの記事を投稿していきます。

データベースを誰でも更新できてしまうので、最低限ではありますが基本のセキュリティ対策はしています。

参考テーマも作成しましたので、興味のある方はダウンロードしてください。

あくまでもwp_insert_post()の使い方の参考として見てもらえたらと思います。

リダイレクトを記述

functions.phpにいろいろな機能を追加していきます。

まず、シングルページアプリケーションとしますので、トップページしか存在しません。

他のページにアクセスしようとすると全てリダイレクトされます。

リダイレクトのための関数set_redirect()を作成し、get_headerに差し込みます。

is_home()の条件分岐はページが表示されてからしか使えないので、get_headerの後で実行させなる必要があります。

プラグインやfunctions.phpに記述する時はご注意ください。

さらにリダイレクトやデータベースを操作するphpは、htmlよりも先に記述する必要がありますので、get_headerのアクションフックは非常に使い勝手が良いのです。

//リダイレクト
add_action('get_header', 'set_redirect');
function set_redirect()
{
   if (!is_home()) {
       wp_redirect(home_url());
   }
}

インサートを作成

この部分で行っている処理は複数あります。

  • セッションをスタートさせる
  • エラーが合った場合セッションに保存
  • 正しいフォームからpostが行われているかチェック
  • postデータが存在するかチェック
  • データベースに値を保存する

こちらも、リダイレクトと同様にget_headerを利用して自作した関数を差し込んでいきます。

インサートするデータはformを利用してpostされてきますので、postデータが存在しない動きません。

emptyを利用してpostデータの有無をチェックしています。

さらに、正しいフォームからちゃんとpostデータ送られてきているかのチェックにwp_verify_nonce()という関数を利用しています。

wordpressでデータベースに値をpostする場合は、この関数で正しいフォームからデータが送られてきているかチェックをするようにしないといけません。

セキュリティ対策の基本です。

もろもろのチェック等でインサートに失敗した場合、セッションにエラーが入るようにしておくと、jsによるアラート表示に役立ちます。

インサートが完了したらセッションを削除し、postデータも削除するためのリダイレクトを行います。

//insertの実行
add_action('get_header', 'set_insert_post');
function set_insert_post()
{
   session_start();
  
   //postデータのチェック
   if (!empty($_REQUEST['my-nonce-field'])
   && wp_verify_nonce($_REQUEST['my-nonce-field'], 'my-nonce')) {
       $my_post = array(
           'post_title' => $_POST['title'],
           'post_content' => $_POST['contnet'],
           'post_status' => 'publish',
           'post_author' => 1,
           'post_category' => $_POST['cats']
       );
 
       // 投稿をデータベースへ追加
       $post_id = wp_insert_post($my_post);
       if ($post_id) {
           session_destroy();
           wp_redirect(home_url());
       } else {
           $_SESSION['error'] = true;
       }
   }
}

入力formの作成

htmlで入力フォームを作成するのですが、今回デザインを整えるためにブートストラップ利用しています。

classがごちゃごちゃ入っていますが、今回の機能には関係ありません。

フォームの項目はこちら。

  • タイトルのテキスト入力
  • カテゴリーのチェックボックス
  • 内容のテキストエリア

チェックボックスはすでに設定されているカテゴリー一覧を関数によってシュルよくしています。

wp_nonce_field()はpostデータのチェックするセキュリティ対策で利用します。

フォームのhtml

<form class="mb-5" action="<?php print home_url(); ?>" method="post">
    <div class="form-group row">
        <label class="col-sm-2 col-form-label" for="label-title">タイトル</label>
        <div class="col-sm-10">
            <input id="label-title" type="text" name="title" class="form-control" value="">
        </div>
    </div>
    
    <div class="form-group row">
        <label class="col-sm-2 col-form-label">カテゴリー</label>
        <div class="col-sm-10">
            <?php $InsertSample->the_list_cats_checkbox(); ?>
        </div>
    </div>

    <div class="form-group row">
        <label class="col-sm-2 col-form-label" for="label-content">内容</label>
        <div class="col-sm-10">
            <textarea id="label-content" class="form-control" name="contnet"></textarea>
        </div>
    </div>

    <?php wp_nonce_field('my-nonce', 'my-nonce-filed'); ?>
    <button type="submit" class="btn btn-primary mb-2">送信</button>
</form>

カテゴリーのチェックボックス

特に説明することもありませんが、hide_emptyをfalseにしておくと、投稿が一見もないカテゴリーも出力できます。

//カテゴリーのチェックボックスを表示
function the_list_cats_checkbox()
{
   $args = array(
       'hide_empty' => false
   );
   $terms = get_terms('category', $args);
   foreach ($terms as $v) {
       print <<< EOT
       <div class="form-check form-check-inline">
           <input id="check-{$v->term_id}" class="form-check-input" name="cats[]" value="{$v->term_id}" type="checkbox">
           <label class="form-check-label" for="check-{$v->term_id}">{$v->name}</label>
       </div>
EOT;
   }
   unset($v);
}

class化してみよう

長くなるのでindex.phpとfunctions.phpの部分だけ抜粋します。

functions.phpの記述

class InsertSample
{
    public function __construct()
    {
        add_action('get_header', array($this, 'header_run'));
    }


    //headerの前に実行
    public function header_run()
    {
        session_start();
        $this->set_redirect();

        if (is_home()) {
            $this->set_insert_post();
        }
    }


    //リダイレクト
    public function set_redirect()
    {
        if (!is_home()) {
            wp_redirect(home_url());
            exit;
        }
    }


    //インサート
    public function set_insert_post()
    {
        //postデータのチェック
        if (!empty($_REQUEST['my-nonce-field'])
        && wp_verify_nonce($_REQUEST['my-nonce-field'], 'my-nonce')) {
            $my_post = array(
                'post_title' => $_POST['title'],
                'post_content' => $_POST['contnet'],
                'post_status' => 'publish',
                'post_author' => 1,
                'post_category' => $_POST['cats']
            );
    
            // 投稿をデータベースへ追加
            $post_id = wp_insert_post($my_post);
            if ($post_id) {
                session_destroy();
                wp_redirect(home_url());
                exit;
            } else {
                $_SESSION['error'] = true;
            }
        } else {
            $_SESSION['error'] = true;
        }
    }


    //カテゴリーのチェックボックを表示
    public function the_list_cats_checkbox()
    {
        $args = array(
            'hide_empty' => false
        );
        $terms = get_terms('category', $args);
        foreach ($terms as $v) {
            print <<< EOT
            <div class="form-check form-check-inline">
                <input id="check-{$v->term_id}" class="form-check-input" name="cats[]" value="{$v->term_id}" type="checkbox">
                <label class="form-check-label" for="check-{$v->term_id}">{$v->name}</label>
            </div>
EOT;
        }
        unset($v);
    }


    //投稿をリストで表示
    public function the_post_list()
    {
        print '<ul class="list-group">';
        $args = array(
            'posts_per_page' => -1
        );
        $posts_data = get_posts($args);
        foreach ($posts_data as $v) {
            $content = apply_filters('the_content', $v->post_content);
            $terms = get_the_terms($v->ID, 'category');
            $cats = '';
            foreach ($terms as $term) {
                $cats .= '<div class="list-inline-item">' . $term->name . '</div>';
            }
            unset($term);
            print <<< EOT
            <li class="list-group-item">
                {$cats}
                <p class="h4">{$v->post_title}</p>
                {$content}
            </li>
EOT;
        }
        unset($v);
        print '</ul>';
    }
}


//classの実行
$InsertSample = new InsertSample();

index.phpの記述

<?php get_header(); ?>

<div class="container mt-5 mb-5">
    <form class="mb-5" action="<?php print home_url(); ?>" method="post">
        <div class="form-group row">
            <label class="col-sm-2 col-form-label" for="label-title">タイトル</label>
            <div class="col-sm-10">
                <input id="label-title" type="text" name="title" class="form-control" value="">
            </div>
        </div>
        
        <div class="form-group row">
            <label class="col-sm-2 col-form-label">カテゴリー</label>
            <div class="col-sm-10">
                <?php $InsertSample->the_list_cats_checkbox(); ?>
            </div>
        </div>

        <div class="form-group row">
            <label class="col-sm-2 col-form-label" for="label-content">内容</label>
            <div class="col-sm-10">
                <textarea id="label-content" class="form-control" name="contnet"></textarea>
            </div>
        </div>

        <?php wp_nonce_field('my-nonce', 'my-nonce-field'); ?>
        <button type="submit" class="btn btn-primary mb-2">送信</button>
    </form>

    <?php $InsertSample->the_post_list(); ?>
</div>

<?php get_footer(); ?>

テーマのサンプルもありますので、興味があったらダウンロードしてください。

質問やミスの指摘などありましたら、お気軽にコメントください。

正社員という奴隷制度に中指を立てるWebエンジニアです。PHPが得意。繋がれた鎖を断ち切るために、自由を取り戻すために、プログラミングスキルを磨く日々です。プログラミングと個人でもできるビジネスについて、情報発信しています。

詳しくはこちら