WordPress:投稿専用画面からユーザーにアイキャッチ画像付きで自由投稿させる

  • ダッシュボード外の投稿フォームを作る
  • 登録ユーザーが投稿できる
  • アイキャッチ画像をアップロードできる

いわばユーザ登録型画像掲示板のような仕様をWordpressで実現したのでそのメモ。

投稿処理

http://takahashifumiki.com/web/programing/2173/
こちらのWordpressの投稿の基本に沿う。
※紹介されているソースには一部ミスがあるので注意。

ちなみに自分の場合、カスタム投稿タイプは設定せず通常の投稿にしたかったので「post_type」はpostとしている。

素直に沿えば通常投稿できるので細かくは割愛。
以下は上記内容ができている前提。

ファイルアップロード

上記の投稿処理に従い、フォーム用テンプレート page-create-thread.php を作っている前提として、そちらのフォームから画像を投稿できるようにする。

<form action="<?php the_permalink();?>" enctype="multipart/form-data" method="post">
~
<tr>
  <th><label>画像</label></th>
  <td><input type="file" name="image" /></td>
</tr>
~

formタグに enctype=”multipart/form-data”を追加し、フォーム内には input type=file を追加する。

次に投稿処理を行う create-thread.php に画像アップの処理を加える。
テキストバリデーションと投稿処理の間に入れると良い。

if (isset($_FILES['image']['error']) && is_int($_FILES['image']['error'])) {
  // ファイルバリデーション
  if (!$_FILES['image']['error']) {

    // サイズ上限チェック
    if ($_FILES['image']['size'] > 1000000) {
      $create_thread_error[] = 'ファイルサイズが大きすぎます。';
    }

    // getimagesizeを利用しMIMEタイプをチェック
    $imageInfo = getimagesize($_FILES['image']['tmp_name']);
    list($orig_width, $orig_height, $image_type) = $imageInfo;
    if ($imageInfo === false) {
      $create_thread_error[] = '画像ファイルではありません。';
    } else {
      $ext = substr($_FILES['image']['name'], strrpos($_FILES['image']['name'], '.') + 1);
      if (false === $ext = array_search(
        $imageInfo['mime'],
        array(
        'jpg' => 'image/jpeg',
        'png' => 'image/png',
        'gif' => 'image/gif',
        ),
        true
      )) {
        $create_thread_error[] = '画像形式が未対応です。';
      }
    }

    $user = wp_get_current_user();
    $upload_dir = wp_upload_dir();
    $image_url = $upload_dir['path'] . '/'. $user->get('user_login').'-'. date(YmdHis) .'.'. $ext;
    if (!move_uploaded_file($_FILES['image']['tmp_name'],$image_url)) {
      $create_thread_error[] = 'ファイル保存時にエラーが発生しました。';
    }
  } else {
    $create_thread_error[] = 'ファイルが選択されていません。';
  }
}

最後のエラー文で画像の投稿は必須としているが、そこはご自由に。
画像の名前も上書きが発生しないよう「ユーザID年月日時分秒.jpg」みたくしていますが、そこもご自由に。

アップした画像をアイキャッチ画像にする

前提として、Wordpress内の投稿処理の順序は下記になる。

  1. 記事を投稿する
  2. メディアファイル(画像)をアップロードする
  3. 記事とメディアファイルを関連付ける

1、2の処理は上記までで行っているので、3のステップにあたる。

http://wordpress.stackexchange.com/questions/40301/how-do-i-set-a-featured-image-thumbnail-by-image-url-when-using-wp-insert-post
上記を参考に create-thread.php に処理を加える。

//アイキャッチ設定
$image_data = file_get_contents($image_url);
$filename = basename($image_url);
if(wp_mkdir_p($upload_dir['path']))
    $file = $upload_dir['path'] . '/' . $filename;
else
    $file = $upload_dir['basedir'] . '/' . $filename;
file_put_contents($file, $image_data);

$wp_filetype = wp_check_filetype($filename, null );
$attachment = array(
    'post_mime_type' => $wp_filetype['type'],
    'post_title' => sanitize_file_name($filename),
    'post_content' => '',
    'post_status' => 'inherit'
);
$attach_id = wp_insert_attachment( $attachment, $file, $post_id );
require_once(ABSPATH . 'wp-admin/includes/image.php');
$attach_data = wp_generate_attachment_metadata( $attach_id, $file );
wp_update_attachment_metadata( $attach_id, $attach_data );

set_post_thumbnail( $post_id, $attach_id );

画像のアップロードは済んでいるので、その画像URLを指定するだけで参考元まんまで動く。

ソース

参考までに自分がテストで作って動作したソースを丸々掲載。
セッション処理も加えてますが、そこは普通にPHPのやり方で。

<?php
/**
 * Template Name: スレッド投稿フォーム
 */
get_header(); ?>
<?php
if(is_user_logged_in()): //Login check
$user = wp_get_current_user();
?>
<?php //echo $title ?>
<form action="<?php the_permalink();?>" method="post" enctype="multipart/form-data">
  <?php
  // セッション処理
  session_start();
  require_once "functions/definition.php";
  $content_txt = "";
  ini_set("session.bug_compat_42", 0);
  ini_set("session.bug_compat_warn", 0);
  if(isset($_SESSION[TITLE])) $content_txt = $_SESSION[TITLE];
  if(isset($_SESSION[CONTENT])) $content_txt = $_SESSION[CONTENT];

  show_thread_error();
  wp_nonce_field('create_thread');

  ?>
  <table class="form-table">
  <tbody>
    <tr>
      <th><label for="title">タイトル</label></th>
      <td><input id="title" type="text" name="title" value="<?php echo $title_txt; ?>" /></td>
    </tr>
    <tr>
      <th><label>画像</label></th>
      <td><input type="file" name="image" /></td>
    </tr>
    <tr>
      <th><label>カテゴリー</label></th>
      <td><?php wp_dropdown_categories(); ?></td>
    </tr>
    <tr>
      <th><label for="content">コメント</label></th>
      <td><textarea id="content" name="content"><?php echo $content_txt; ?></textarea></td>
    </tr>
  </tbody>
  </table>
  <p class="submit"><input type="submit" value="投稿する" /></p>
</form>
<?php else: //Login check else ?>
<p><a href="<?php echo wp_login_url(get_permalink()); ?>">ログイン</a>してください。</p>
<?php
endif; //Login check
get_footer();
?>
<?php
/**
 * テンプレートが読み込まれる直前で実行される
 */

global $create_thread_error;
$create_thread_error = array();

// セッション処理
session_start();
require_once "definition.php";
$_SESSION[TITLE] = $_POST[TITLE];
$_SESSION[CONTENT] = $_POST[CONTENT];

// 投稿する
function _my_create_thread(){
  if(
    is_page('create-thread')  //create-thredページチェック
      &&
    is_user_logged_in() //ログインチェック
      &&
    isset($_POST['_wpnonce']) //wpnonceチェック
      &&
    wp_verify_nonce($_POST['_wpnonce'], 'create_thread')  //wpnoceベリファイ
  ){

    // バリデーション
    global $create_thread_error;
    if(!isset($_POST['title']) || empty($_POST['title'])){
      $create_thread_error[] = 'タイトルが空白です。';
    }
    if(!isset($_POST['content']) || empty($_POST['content'])){
      $create_thread_error[] = '本文が空です。';
    }

    if (isset($_FILES['image']['error']) && is_int($_FILES['image']['error'])) {
      // ファイルバリデーション
      if (!$_FILES['image']['error']) {

        // サイズ上限チェック
        if ($_FILES['image']['size'] > 1000000) {
          $create_thread_error[] = 'ファイルサイズが大きすぎます。';
        }

        // getimagesizeを利用しMIMEタイプをチェック
        $imageInfo = getimagesize($_FILES['image']['tmp_name']);
        list($orig_width, $orig_height, $image_type) = $imageInfo;
        if ($imageInfo === false) {
          $create_thread_error[] = '画像ファイルではありません。';
        } else {
          $ext = substr($_FILES['image']['name'], strrpos($_FILES['image']['name'], '.') + 1);
          if (false === $ext = array_search(
            $imageInfo['mime'],
            array(
            'jpg' => 'image/jpeg',
            'png' => 'image/png',
            'gif' => 'image/gif',
            ),
            true
          )) {
            $create_thread_error[] = '画像形式が未対応です。';
          }
        }

        $user = wp_get_current_user();
        $upload_dir = wp_upload_dir();
        $image_url = $upload_dir['path'] . '/'. $user->get('user_login').'-'. date(YmdHis) .'.'. $ext;
        if (!move_uploaded_file($_FILES['image']['tmp_name'],$image_url)) {
          $create_thread_error[] = 'ファイル保存時にエラーが発生しました。';
        }
      } else {
        $create_thread_error[] = 'ファイルが選択されていません。';
      }
    }

    //エラーが無ければ投稿処理
    if(empty($create_thread_error)){
      $post_id = wp_insert_post(array(
        'post_title' => (string)$_POST['title'],
        'post_content' => (string)$_POST['content'],
        'post_status' => 'publish',
        'post_author' => get_current_user_id(),
        'post_type' => 'post',
        'post_category' => array(intval($_POST['cat']))
      ), true);

      //アイキャッチ設定
      $image_data = file_get_contents($image_url);
      $filename = basename($image_url);
      if(wp_mkdir_p($upload_dir['path']))
          $file = $upload_dir['path'] . '/' . $filename;
      else
          $file = $upload_dir['basedir'] . '/' . $filename;
      file_put_contents($file, $image_data);

      $wp_filetype = wp_check_filetype($filename, null );
      $attachment = array(
          'post_mime_type' => $wp_filetype['type'],
          'post_title' => sanitize_file_name($filename),
          'post_content' => '',
          'post_status' => 'inherit'
      );
      $attach_id = wp_insert_attachment( $attachment, $file, $post_id );
      require_once(ABSPATH . 'wp-admin/includes/image.php');
      $attach_data = wp_generate_attachment_metadata( $attach_id, $file );
      wp_update_attachment_metadata( $attach_id, $attach_data );

      set_post_thumbnail( $post_id, $attach_id );

      //データの挿入に成功していたら移動
      if(!is_wp_error($post_id)){
        //ページを移動
        header('Location: '.get_permalink($post_id));
        die();
      } else {
        $create_thread_error[] = '投稿時にエラーが発生しました。'.$post_id->get_error_message();
      }
    }
  }
}
add_action('template_redirect', '_my_create_thread');

/**
 * スレッド作成画面でエラーがあれば表示
 * @global array $create_thread_error
 */
function show_thread_error(){
  global $create_thread_error;
  if(!empty($create_thread_error)){
    echo '<div id="error">';
    echo implode('<br />', $create_thread_error);
    echo '</div>';
  }
}
?>

筆者について

KaBuKi
ゲームとジョジョを愛するファミッ子世代。好きな言葉は「機能美」。
公私ともにWebサービスを作る系男子。