kohanaのテスト12-8・・・WordPressの新規投稿ページを作る
新規投稿ページの移植ではかなり引っ掛かる所があります。順を追って説明していきます。
準備作業
HTML 中に次の記述があります。
<script type='text/javascript' src='http://localhost/wordpress/wp-includes/js/tinymce/wp-tinymce.php?c=1&ver=345-20111127'></script>
TinyMCE の javascript を読み込むのにわざわざ専用の php ファイルを呼んでいます。これは意味不明です。標準的には圧縮ファイル wp-tinymce.js.gz を読み込みますが、ケースによっては非圧縮の wp-tinymce.js を読み込みます。
不思議なことにこの両者は中身が違います。で、wp-tinymce.js だと正常動作しません。ということで、wp-tinymce.js.gz を解凍して、wp-tinymce.js を置き換えます。
新規投稿ページの HTML には長々とスクリプトが記述されています。これは見苦しいので、スクリプトごとにファイル化して、定義ファイルに登録してローダーで読み込むようにしました。定義ファイルは次のように追記しています。
・kohana/application/config/wp-js-css.php の追記部分
// Added js 'tinymce' => '/includes/wp/includes/js/tinymce/wp-tinymce.js', 'tinymce-langs-ja' => '/includes/wp/includes/js/tinymce/langs/wp-langs-ja.js', 'tinymce-preinit' => '/includes/wp/includes/js/tinymce/tiny_mce_preinit.js', 'tinymce-setting' => '/includes/wp/includes/js/tinymce/tiny_mce_setting.js', 'commonl10n' => '/includes/wp/includes/js/commonl10n.js',
これらのスクリプトにはパスが直接書いてあったりしますので、これは適切に変更します。
モデル
今日は投稿を記録する部分のみです。読み出し部分は次回。
・kohana/application/classes/model/test12/posts.php
データベースを移行する時に使った .sql ファイルのテーブル wp332_posts 部分から全てのカラムの名前を抜き取って、全てのデフォルト値を設定します。メソッド postnew はデフォルトを上書きしたいキーと値の配列を受け取って処理します。こうしておけばデータベースの書き込みエラーは発生しようがないと思います。
<?php defined('SYSPATH') OR die('No direct access allowed.'); class Model_Test12_posts extends Model { public function postnew($array) { $date = Date::formatted_time(); $post = array( 'ID' => '', 'post_author' => '0', 'post_date' => $date, 'post_date_gmt' => $date, 'post_content' => 'NOT POSTED!!!', 'post_title' => 'NOT POSTED!!!', 'post_excerpt' => '', 'post_status' => 'publish', 'comment_status' => 'open', 'ping_status' => 'open', 'post_password' => '', 'post_name' => '', 'to_ping' => '', 'pinged' => '', 'post_modified' => $date, 'post_modified_gmt' => $date, 'post_content_filtered' => '', 'post_parent' => '0', 'guid' => '', 'menu_order' => '0', 'post_type' => 'post', 'post_mime_type' => '', 'comment_count' => '0', ); foreach ($array as $key => $value) { $post[$key] = $value; } $id = DB::insert(array_keys($post)) ->values($post) ->table('wp332_posts') ->execute(); return $id; } } ?>
Auth ドライバに機能追加
ユーザー名を渡したらユーザーIDを返すメソッドを追加します。
・kohana/application/classes/auth/wplogin.php に追加
// Get the ID for a username. public function user_ID($username) { $userdata = DB::select('ID', 'user_login') ->from('wp332_users') ->where('user_login', '=', $username) ->execute(); $id = $userdata->get('ID', FALSE); return $id; }
ビュー
・スタイルシート、スクリプトを読み込んでいる部分を修正します。記事の自動保存機能はじゃまなので、スクリプト autosave は読み込まないことにします。
・WordPress は記事のタイトルを記事そのものが空でも投稿できちゃいます。これは気に入らないので、エラーチェックします。で、エラーを表示する部分を作ります。
<h2>新規投稿を追加</h2> <?php if ($errors): echo '<div id="message" class="updated">' . "\n"; foreach ($errors as $value) { echo "<strong>エラー</strong>: $value<br />" . "\n"; } echo '</div>' . "\n"; endif; ?>
エラーの場合に元の記事を戻す部分を書きます。
<input type="text" name="post_title" size="30" tabindex="1" value="<?php echo $post_title ?>" id="title" autocomplete="off" /> <textarea class="wp-editor-area" rows="20" tabindex="1" cols="40" name="content" id="content" ><?php echo $content ?></textarea>
スクリプトを多数ロードしている部分は次のように一本化しています。引数に c=1 や c=gzip を指定しても動作します。localhost でテストする限り速度の差を感じませんが、通信回線が遅い場合を考慮して設定すると良いかもしれません。
<script type='text/javascript' src='/kohana/loadjs?load=commonl10n,admin-bar,hoverIntent,common,jquery-color,schedule,wp-ajax-response,suggest,wp-lists,jquery-ui-core,jquery-ui-widget,jquery-ui-mouse,jquery-ui-sortable,postbox,post,thickbox,media-upload,word-count,editor,quicktags,jquery-ui-resizable,jquery-ui-draggable,jquery-ui-button,jquery-ui-position,jquery-ui-dialog,wpdialogs,wplink,wpdialogs-popup,wp-fullscreen,tinymce-preinit,tinymce,tinymce-langs-ja,tinymce-setting'></script>
修正部分はまだあるかもしれませんが、あとは自分でチェックしましょう。
コントローラ
・kohana/application/classes/controller/test12/postnew.php
冒頭でログインチェックして、OKならユーザーIDをゲットしています。
タイトルや記事の文字数が無制限ではいたずらされちゃいますから、ある程度で制限すべきだと思います。尚、文字数はバイト数ではなく、本当の文字の数で判定しています。
注1:5月18日修正
エラー時に記事本文をテキストエリアに戻す時に HTML エスケープはしないことにしました。TynyMCE は HTML エディターなんですね・・・(^^;;;
で、XSS 攻撃対策は TynyMCE がちゃんとやってくれているようです。
<?php defined('SYSPATH') OR die('No direct access allowed.'); class Controller_Test12_postnew extends Controller { public function action_index() { $loginuser = Auth_Wplogin::instance()->get_user(); if (!$loginuser) $this->request->redirect('test12'); $user_ID = Auth_Wplogin::instance()->user_ID($loginuser); $model = Model::factory('test12_posts'); if (isset($_POST['post_title'])) { $post = Validation::factory($_POST) ->rule('post_title', 'not_empty', array(':value', 'タイトル')) ->rule('post_title', 'max_length', array(':value', 100)) ->rule('content', 'not_empty', array(':value', '記事')) ->rule('content', 'max_length', array(':value', 10000)); $posts = $post->data(); if ($post->check()) { $post_array = array( 'post_author' => $user_ID, 'post_title' => $posts['post_title'], 'post_content' => $posts['content'], ); $model->postnew($post_array); $this->request->redirect('test12'); } $errors = $post->errors('test12'); $post_title = HTML::chars($_POST['post_title']); $content = $_POST['content']; } else { $errors = ''; $post_title = ""; $content = ""; } $view = view::factory('test12/postnew/postnew'); $view->errors = $errors; $view->head02 = view::factory('test12/postnew/head02'); $view->adminmenu = view::factory('test12/postnew/adminmenu'); $view->help = view::factory('test12/postnew/help'); $view->screen_option = view::factory('test12/postnew/screen_option'); $view->form_1 = view::factory('test12/postnew/form_1'); $view->form_1->post_title = $post_title; $view->form_1->content = $content; $view->form_2 = view::factory('test12/postnew/form_2'); $view->wpadminbar = view::factory('test12/postnew/wpadminbar'); $view->wpadminbar->loginuser = $loginuser; $view->form_3 = view::factory('test12/postnew/form_3'); $view->fullscreen = view::factory('test12/postnew/fullscreen'); $this->response->body($view); } } ?>
動作試験
トップページの新規投稿へのリンクは /kohana/test12_postnew とします。ログインして記事を投稿するとデータベースに記事が記録されます。トップページの記事表示部分をまだ書いていないので、phpMyAdmin でチェックします。