プログラム研究ブログ

propansystemの研究ブログ

ここまで準備してきたプラグインのphpに対し、
ここからは「POEDIT」というツールを使い、POファイルを作成します。

POEDDTIはこちらからダウンロードします。
(このブログを書いた時点で「Poedit-2.0.6-setup.exe」でした)

インストールして起動すると次のようになります。

起動後にメニュー→ファイル→設定から、「翻訳者に関する情報」を登録しておきます。

国際化対応その5は、プラグインのプログラムのコンストラクタ内で言語ファイルを読み込むように設定します。

具体的には以下のようにに記述します。

$plugin_dir = basename(dirname(__FILE__));

load_plugin_textdomain( 'プラグイン名', 'wp-content/plugins/' . $plugin_dir, $plugin_dir );

プラグイン名については、今回は「SamplePlugin1」というベースネームがあるので、以下のように書きます。

$plugin_dir = basename(dirname(__FILE__));

load_plugin_textdomain( 'SamplePlugin1, 'wp-content/plugins/' . $plugin_dir, $plugin_dir );

翻訳可能文字列を選定し、文字列を関数コールで囲みます。

例として

例1
$hello = __("Hello, dear user!");

例2
_e("TEST!")

のように記載します。

「__」関数で囲んだメッセージが翻訳対象となります。
「_e」関数で囲うと、ブラウザ出力を行います。

国際化対応するその3は、テキストドメインの決定です。

wordpressがプラグインを識別する為に、ユニークな名前にします。

プラグイン名にすると分かりやすく、運用がしやすいです。

今回は、これまで作ってきたプラグインの「SamplePlugin1」という名前にします。

また、この名前の決定は、後ほど出てくるPOファイルやMOファイルになります。

前回の作成したプラグインを国際化する対応について、
もう少し詳しく落とし込みます。

詳しくは公式ドキュメントのこちらのページに記載されています。

これまでに作成してきたプラグインは、以下のディレクトリになります。

/ワードプレスをインストールしたディレクトリ/wp-content/plugins/SamplePlugin1/

まず、このディレクトリ内に多言語用のディレクトリを新規作成します。

/ワードプレスをインストールしたディレクトリ/wp-content/plugins/SamplePlugin1/languages

WordPressの国際化対応をするには、ライブラリでGNU gettextを使用します。

■POTファイル
Portable Object Templateの略です。
翻訳対象となるメッセージと翻訳結果を保存するファイルのテンプレートとなるものです。

■POファイル
翻訳対象となるメッセージと翻訳結果を保存します。

■MOファイル
Machine Objectの略です。
翻訳結果を表示する為に必要になるファイルです。

実際に国際化する為には、上記の概念を把握した上で作成していきます。

前回まで作成したショートコードをさらに改修します。

ショートコードを利用する側で、次のような記載の場合があります。

[samplelist3]なんらかの記述[/samplelist3]

この場合は、以下のような関数になります。

/**
 * ショートコード(その3)
 */
function samplelistFunction3($param, $content = '')
{
    
    if ($content == "") {
        return;
    } else {
        extract(
            shortcode_atts(
                array("class" => "default"),
                $atts
            )
        );
        
        return '<p class="' . esc_attr($class) . '">' . esc_html($content) . '</p>';
    }
    
}
 
add_shortcode('samplelist3', 'samplelistFunction3');

ショートコードを改修する

このブログで実装を進めてきたプラグインについて、以前の記事になりますが、ショートコードを実装しました。

その時に実装した内容はこちらの記事になります。

今回はその時に実装したショートコードプラグインを改造してみます。

まず、前回のコードはちなみに下記のようになっています。

/**
 * ショートコード
 */
function samplelistFunction()
{
    //データ一覧
    $disp_html =<<< EOL
<form action="" method="post">
<h2>データ一覧(ショートコードテスト)</h2>

<div class="wrap">

<table class="wp-list-table widefat striped posts">
    <tr>
        <th nowrap>ID</th>
        <th nowrap>名前</th>
        <th nowrap>登録日時</th>
    </tr>
EOL;

    global $wpdb;

    $tbl_name = $wpdb->prefix . 'sample_mst';
    $sql = "SELECT * FROM {$tbl_name} ORDER BY id;";
    $rows = $wpdb->get_results($sql);

    foreach($rows as $row) {

$disp_html .=<<<EOL
    <tr>
        <td>{$row->id}</td>
        <td>{$row->sample_name}</td>
        <td>{$row->create_date}</td>
        <td>
    </tr>
EOL;
    }

    $disp_html .=<<< EOL
</table>

</div>

</form>
EOL;

    return $disp_html;
}

add_shortcode('samplelist', 'samplelistFunction');

上記のコードを投稿側で使用するには、

[samplelist]

のように書きます。

その際に、ショートコードのパラメータ部分を記述し、プログラム側に値として渡す方法を書きます。

[samplelist2 text="TEST"]

プラグイン側の記述も同様にパラメータを受け取るように変更します。

/**
 * ショートコード(その2)
 */
function samplelistFunction2($param)
{
    $default_param = array(
        "text" => "default text"
    );
    
    $merged_param = shortcode_atts($default_param, $param);
    extract($merged_param);
    
    return esc_html($text);
}

add_shortcode('samplelist2', 'samplelistFunction2');

上記のように実装し、投稿時には

[samplelist2 text="テスト値"]

のようにショートコードを使うことができます。

実際には値を渡す他に、IDやプラグインの挙動を制御するパラメータを渡す用途があるので、設計によって仕様を決めて実装をします。

作成中のウィジェットは、主にユーザ側への表示でしたが、このウィジェットに対し、管理画面側でなんらかの値を登録&更新する仕組みを実装します。

ウィジェットのソース内に以下のメソッドを追加します。

/**
 * 管理画面側のパラメータ調整用コード
 */
public function form($par)
{
    //入力された文字列(title)を取得
    if (isset($par["title"])) {
        $title = esc_attr($par["title"]);
    } else {
        $title = "";
    }

    //フォーム用のIDを取得
    $title_id = $this->get_field_id('title');
    
    //フォーム用のnameを取得
    $title_name = $this->get_field_name('title');
    
    //フォーム部分の表示
    echo <<<EOL
<label for="{$title_id}"><?php echo _e('Title:'); ?></label>
<input type="text" class="widefat" id="{$title_id}" name="{$title_name}" value="{$title}">
EOL;
}

こうすることで、管理画面で追加したウィジェットの部分に更新用のフォームが表示されます。

仮に「title」というパラメータ名として話を進めます。

上記のコードを書いた後に管理画面にアクセスすると、次のような画面になります(赤枠部分が追加箇所)。

この表示されたフォーム部分に対し、テキストを入力し保存ボタンを押します。

すると、保存しました。というメッセージになり、値が更新されます。

更新後は

<label for="{$title_id}"><?php echo _e('Title:'); ?></label>

というラベル部分の「echo _e(‘title’);」の箇所が表示され、入力した値が確認できます。

更新した値はウィジェット表示側のメソッド「public function widget」で$parの変数に格納されているので、下記のようにechoすることでユーザ側画面のサイドバーに表示されます。

public function widget($args, $par)
{
    echo $args["before_widget"];

    echo $args["before_title"];
    echo "これはウィジェットでの表示です";
    echo $args["after_title"];

    echo "ここは中身です";
    
    echo esc_html($par["title"]);

    echo $args["after_widget"];
    
}

前回作成したウィジェットに、ブログ画面側の表示ロジックを入れてみます。

前回のソースコードを基に、public function widgetメソッドに対し、次のように記載します。

public function widget($args, $par)
{
    echo $args["before_widget"];

    echo $args["before_title"];
    echo "これはウィジェットでの表示です";
    echo $args["after_title"];

    echo "ここは中身です";
    echo $args["after_widget"];
}

次に、管理側の外観→ウィジェットの画面で、ウィジェットエリアに作成したsampleのウィジェットをセットします。

こうすることで、ブログ側のサイドメニューにウィジェットを表示することができます。

ウィジェットを作成する

前回までは主にプラグインの作成についてやってきましたが、ここからは若干方針を変更して、ウィジェットの作成をやってみます。

まず、ウィジェットを作りにあたり、プラグイン用のフォルダに新規ファイルを作成します。

分かりやすいようにサーバ上の以下のフォルダ「SamplePlugin1」直下に新規ファイルを作成します。

/wordpressがインストールされているフォルダ/wp-content/plugins/SamplePlugin1

上記の場所に「SampleWidget1.php」を作成し、中には次のように記載します。

<?php

/*
Plugin Name: SampleWidget1
Plugin URI:  http://
Description: サンプルウィジェット。
Version:     1.0
Author:      sample
Author URI:  http://
License:     GPL2
License URI: https://www.gnu.org/licenses/gpl-2.0.html
*/

add_action(
    'widgets_init',
    create_function('', 'return register_widget("sample_widget");')
);

/**
 * Widget Class
 */
class sample_widget extends WP_Widget
{
    function __construct()
    {
        
        $widget_ops = array("description" => "Sample");
        $control_ops = array("width" => 400, "height" => 300);
        
        parent:: __construct(
            false,
            "Sample",
            $widget_ops,
            $control_ops
        );
        
    }
    
    public function widget($args, $par)
    {
        
    }
    
}

この記述だけで、管理画面のプラグイン画面には次のように表示されます。

その後「有効化」リンクを押して有効にします。

有効化した後は、管理画面の「外観」の中の「ウィジェット」というリンクが表示されるので、画面を開きます。

次に、管理画面の右側を確認すると、次のようなSampleウィジェットが表示されます。

この時、注意が必要なのは、テーマ側の作りによって、ウィジェットをサポートしていないと、管理メニュー内に「ウィジェット」というメニュー項目そのものが表示されなくなります。

ウィジェットを使う場合は、テーマ側の構造も把握しておくと良いです。

HTTP APIの検証(その4)

前回に引き続き、HTTP APIの検証をします。

その4としてwp_remote_retrieve_response_code と wp_remote_retrieve_response_messageを試してみます。

//HTTP APIのテスト
$url = "http://hogehoge.fuga/";
$response = wp_remote_get($url, $args);

$return_code = wp_remote_retrieve_response_code($response);
var_dump($return_code);

$return_message = wp_remote_retrieve_response_message($response);
var_dump($return_message);

上記のコードを実行すると、以下のような結果が返ってきます(状況によります)

200

OK

また、wp_remote_get関数を使う場合の注意としては、$urlをesc_url()の関数を使う必要があります。
これはURL内にエスケープが必要な文字列があった場合に、安全に関数を動作させる為に必要になります。

具体的には、以下のように書くと良いです。

//HTTP APIのテスト
$url = "http://hogehoge.fuga/";
$response = wp_remote_get(esc_url($url), $args);

HTTP APIの検証(その3)

前回に引き続き、HTTP APIの検証を行います。

3回目の関数はwp_remote_retrieve_headeresです。
前回同様、wp_remote_getした後に、この関数の戻り値をvar_dumpしてみます。

実際に下記のように書きました(ドメイン部分のみダミー値です)

//HTTP APIのテスト
$url = "http://hogehoge.fuga/";
$response = wp_remote_get($url, $args);

$return_value3 = wp_remote_retrieve_headers($response);
var_dump($return_value3);

var_dumpした結果、次のようになります。

object(Requests_Utility_CaseInsensitiveDictionary)[6275]
  protected 'data' => 
    array (size=9)
      'date' => string 'Sun, 04 Mar 2018 09:23:35 GMT' (length=29)
      'server' => string 'Apache' (length=6)
      'expires' => string 'Thu, 19 Nov 1981 08:52:00 GMT' (length=29)
      'cache-control' => string 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0' (length=62)
      'pragma' => string 'no-cache' (length=8)
      'set-cookie' => string 'PHPSESSID=547f926e3c6f4ec48bbc4966fb60a386; path=/' (length=50)
      'vary' => string 'Accept-Encoding,User-Agent' (length=26)
      'content-encoding' => string 'gzip' (length=4)
      'content-type' => string 'text/html; charset=UTF-8' (length=24)

結果表示をブラウザで確認したので、上記の値が全てではないかもしれませんが、取得項目はおおよそ把握できます。
詳しい出力結果はログに出力する等の工夫が必要です。

wp_remote_retrieve_headerでは、取得する項目を第二引数で指定する代わりに、wp_remote_retrieve_headersではヘッダー情報の全体を一気に取得してくる。という点が大きく異なります。

それぞれで使用する場面によって適切な使い方をする必要がありそうです。

HTTP APIの検証(その2)

前回の投稿に引き続き、HTTP APIの検証を行います。

前回は「wp_remote_retrieve_header」の関数を試しましたが、今回は「wp_remote_retrieve_body」を書いてみます。

//HTTP APIのテスト
$url = "http://hogehoge.fuga/";
$response = wp_remote_get($url, $args);

$return_value = wp_remote_retrieve_body($response);

最後の「$return_value」をvar_dumpすると、相手先サーバから取得してきたサイトのHTMLソースが格納されています。

利用方法は開発場面により応用が必要ですが、手軽に外部サーバの情報を取得できる点は便利な反面、むやみにアクセスしすぎない等の配慮が必要になります。

HTTP APIについての検証

前回の「HTTP API」について、実際のコードを書いて動作させて検証してみます。

まず、「wp_remote_get」について書いてみます。

プラグイン内の任意の箇所に以下のようなコードを書きました。(URLはダミーに置き換えています)

//HTTP APIのテスト
$url = "http://hogefuga.fuga/";
$response = wp_remote_get($url, $args);

このコードを実行し、$responseの値をvar_dumpで内容を見ると、以下のような結果が返ってきます。
長いですが、全て記載します。

Array
(
    [headers] => Requests_Utility_CaseInsensitiveDictionary Object
        (
            [data:protected] => Array
                (
                    [date] => Fri, 02 Mar 2018 15:04:02 GMT
                    [server] => Apache
                    [expires] => Thu, 19 Nov 1981 08:52:00 GMT
                    [cache-control] => no-store, no-cache, must-revalidate, post-check=0, pre-check=0
                    [pragma] => no-cache
                    [set-cookie] => PHPSESSID=1b6419888d849d81ce51d2cec9ddd499; path=/
                    [vary] => Accept-Encoding,User-Agent
                    [content-encoding] => gzip
                    [content-type] => text/html; charset=UTF-8
                )

        )

    [body] => 
    [response] => Array
        (
             => 200
            [message] => OK
        )

    [cookies] => Array
        (
            [0] => WP_Http_Cookie Object
                (
                    [name] => PHPSESSID
                    [value] => 1b6419888d849d81ce51d2cec9ddd499
                    [expires] => 
                    [path] => /
                    [domain] => hogefuga.fuga
                )

        )

    [filename] => 
    [http_response] => WP_HTTP_Requests_Response Object
        (
            [response:protected] => Requests_Response Object
                (
                    [body] => 
                    [raw] => HTTP/1.1 200 OK
Date: Fri, 02 Mar 2018 15:04:02 GMT
Server: Apache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Set-Cookie: PHPSESSID=1b6419888d849d81ce51d2cec9ddd499; path=/
Vary: Accept-Encoding,User-Agent
Content-Encoding: gzip
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
                  [headers] => Requests_Response_Headers Object
                        (
                            [data:protected] => Array
                                (
                                    [date] => Array
                                        (
                                            [0] => Fri, 02 Mar 2018 15:04:02 GMT
                                        )

                                    [server] => Array
                                        (
                                            [0] => Apache
                                        )

                                    [expires] => Array
                                        (
                                            [0] => Thu, 19 Nov 1981 08:52:00 GMT
                                        )

                                    [cache-control] => Array
                                        (
                                            [0] => no-store, no-cache, must-revalidate, post-check=0, pre-check=0
                                        )

                                    [pragma] => Array
                                        (
                                            [0] => no-cache
                                        )

                                    [set-cookie] => Array
                                        (
                                            [0] => PHPSESSID=1b6419888d849d81ce51d2cec9ddd499; path=/
                                        )

                                    [vary] => Array
                                        (
                                            [0] => Accept-Encoding,User-Agent
                                        )

                                    [content-encoding] => Array
                                        (
                                            [0] => gzip
                                        )

                                    [content-type] => Array
                                        (
                                            [0] => text/html; charset=UTF-8
                                        )

                                )

                        )

                    [status_code] => 200
                    [protocol_version] => 1.1
                    [success] => 1
                    [redirects] => 0
                    [url] => http://hogefuga.fuga/
                    [history] => Array
                        (
                        )

                    [cookies] => Requests_Cookie_Jar Object
                        (
                            [cookies:protected] => Array
                                (
                                    [PHPSESSID] => Requests_Cookie Object
                                        (
                                            [name] => PHPSESSID
                                            [value] => 1b6419888d849d81ce51d2cec9ddd499
                                            [attributes] => Requests_Utility_CaseInsensitiveDictionary Object
                                                (
                                                    [data:protected] => Array
                                                        (
                                                            [path] => /
                                                            [domain] => hogefuga.fuga
                                                        )

                                                )

                                            [flags] => Array
                                                (
                                                    [creation] => 1520003042
                                                    [last-access] => 1520003042
                                                    [persistent] => 
                                                    [host-only] => 1
                                                )

                                            [reference_time] => 1520003042
                                        )

                                )

                        )

                )

            [filename:protected] => 
            [data] => 
            [headers] => 
            [status] => 
        )

)

これはサーバから返された結果になり、全ての結果情報が格納されているようです。

この中にはレスポンスヘッダやHTMLのbody内の文字列(上記の結果からは削除してあります)、などのコンテンツデータも取得できました。

この結果に対し、wordpressでは結果内容を簡単に解析するヘルパー関数があるようです。

ヘルパー関数の例を記載します。

//本文を取得
wp_remote_retrieve_body()

//ヘッダの値を取得
wp_remote_retrieve_header()

//全てのヘッダ情報を取得
wp_remote_retrieve_headers()

//ステータスコードを取得
wp_remote_retrieve_response_code()

//ステータスメッセージを取得
wp_remote_retrieve_response_message()

上記のどの命令を使うかは、場面により異なりますが、
まず、検証の為に「wp_remote_retrieve_header()」を使ってみます。

先ほど冒頭で書いた「wp_remote_get」の結果に対し、使ってみます。

//HTTP APIのテスト
$url = "http://hogefuga.fuga/";
$response = wp_remote_get($url, $args);

//ここで使用する
$header_value = wp_remote_retrieve_header($response, "date");

第二引数の「date」は、取得したいヘッダーの項目名を指定しています。別の項目名でもOKです。

この処理を実行した際、「$header_value」の変数には

Fri, 02 Mar 2018 15:20:49 GMT

等という値が取得されています。

本来であれば、ヘッダーの値を取得する前に、ステータスチェック等を行い、その上で値を取得する。等の対策が必要になってきます。

HTTP APIについて

HTTP APIは、外部サーバに対してHTTP接続を行うAPIのようです。
実際に書いてみないと分からないことが多いので、まずは試しながら動きを確認してみます。

公式ドキュメントはこちらを参考にしています。

HTTP APIの関数は以下のものがあります。

wp_remote_get()
wp_remote_post()
wp_remote_haed()
wp_remote_request()

まずはドキュメントを読み、実際に試していきます。

Transients APIについて

前回の投稿と似た機能を持つAPIを調査しました。

Transients APIというAPIで、ドキュメントはこちらのサイトになります。

このAPIは、データを一時的にデータベースへ保存するAPIで、
保存期間に有効期限を設定し、有効期限がすぎると削除されることが特徴です。

関数としては、次のものを使います。
それぞれ、データ保存時と、データ取得時です。

データ保存時
set_transient($transient, $value, $expiration);

第1引数は保存名(キー名のようなもの)、第2引数は値を表し、第3引数は有効期限の秒数を指定します。
データ取得時
get_transient($transient);

これらは、短時間のデータ保存が必要な場面で使用することが良さそうです。
実践で必要な場面があったら試す予定です。

WordPressAPIについて

wordpressが標準装備していて、プラグインのプログラム内から呼び出して使用できるAPIがあります。

数あるAPIの中から、代表的なAPIを実際にプログラムして、使ってみます。

まずは、Options API という値を保持する為のAPIを使ってみます。
これまで作ってきたプラグインの画面遷移時の動きを利用して、画面遷移の間で値が保持できているかを確認してみます。

まず、データ一覧画面で

update_option("test", "a");

という記述を行い、これを登録画面→確認画面で、取得して表示してみます。

次に、登録確認画面側に、以下のように記述します。

$test_value = get_option("test");
echo $test_value; //内容チェック用に強引に出力する

これで、新規登録後の確認画面で「a」という文字列が表示されることが確認できました(画面キャプチャは省略します)。

保持したデータを削除するには

delete_option("test");

という記述で値を消すことができます。

update_optionと同様のAPIにadd_optionというAPIがあります。
これは画面アクセス時に対し、update_optionはまとめてデータ取得するのに対し、add_optionはget_optionを行う度にデータベースへ問い合わせが発生します。(add_optionの第4引数を使用時)

厳密に言えば、add_optionを多用すると、パフォーマンスが下がる原因になるようです。

これまでの開発ではデータ登録時のエラー処理は、古典的(?)な書き方で入力チェック→エラー内容表示を行っていました。

wordpressには元々エラー処理用のクラスがあるので、それに置き換えてみようと思います。

まずは、入力画面から登録ボタンを押した際の、確認画面の処理を見直します。

//エラー処理を入れる為のオブジェクト生成
$error = new WP_Error();

//入力値チェック(複数のエラーチェックをここで行う)
if (!strlen($_POST["sample_name"])) {
    $error->add("error", "名前を入力してください");
}
if (!strlen($_POST["sample_text"])) {
    $error->add("error", "テキストを入力してください");
}

//エラーコードがある場合は、登録画面を再表示する
if ($error->get_error_code()) {
    //ここで改めて登録フォームを表示する
}

まず、「$error = new WP_Error();」とすることで、エラー処理用のクラスを呼び、オブジェクトを生成しておきます。

次に、入力値チェックを行います。
入力値のチェック方法は色々あると思いますが、ここでは「strlen」を使って単純に文字列(の長さ)があるか無いかで判定しています。
(チェック用の関数の使い方は、別方法がありますが、ここでは割愛いたします)

最後に、「$error->get_error_code()」でエラーだった場合のコードを取得し、エラー表示を行うか、どうかの判定をします。

エラーだった場合は、改めて登録フォームを表示します。

次に、エラー時の登録フォーム側のプログラムを調整します。

//エラー処理
if ($error->get_error_codes()) {
    echo "<div class='error'>";
    echo "<ul>";
    foreach ($error->get_error_messages() as $value) {
        echo "<li>" . esc_html($value) . "</li>";
    }
    echo "</ul>";
    echo "</div>";
}

$errorオブジェクトを渡し、エラーコードの有無を判定します。
エラーだった場合、エラー内容をエラーの個数分表示しています。

具体的な画面は次のようになります。

入力フォームの初期画面

エラーだった場合の再表示画面

エラーメッセージの表示時のクラス名

<div class='error'>

はwordpressに標準搭載されているcssのクラス名なので、画面のエラー文言の表現が統一されて便利です。

また、

<div class='updated'>

というクラス名もあり、その場合は正常に更新されたケースで使用するとよいです。

これまでに作成したプラグインは、データ登録画面で、入力フォームを表示し、次の画面で内容チェック、その後に完了画面を表示する。という一連の動作になっています。

この時、入力フォームから確認画面へ遷移する際のセキュリティとして、CSRF攻撃がされる場面が想定されます。

このCSRF攻撃に対応する為に、対策を入れます。
具体的には、入力画面のform開始タグの直下に、以下の命令を書きます。

<?php wp_nonce_field("my-nonce-key", "my-form"); ?>

また、確認画面側では、次のように書いて、CSRFのチェックを行います。

//CSRF対策用のチェック
if (isset($_POST["my-form"]) && $_POST["my-form"]) {
    if (check_admin_referer("my-nonce-key", "my-form")) {
        //問題がなければ、ここで処理を続行
        
    }
}

ポイントとなる箇所だけを書きましたが、フォーム内に「wp_nonce_field」を、確認画面のチェック処理で「check_admin_referer」を、それぞれ使うということで、覚えておいてよいかと思います。

前回の投稿ではメディアアップローダの画面を利用したファイルのアップロードを書きましたが、今回は単純なプログラムによるファイルのアップロードを書きます。

プラグインを作成する方向性としては、無意味な実装になるかもしれませんが、ここは実験がてらやってみます。

まず、作成中のプラグインのTOP画面にファイルアップロード用のボタンを追加します。

    function disp()
    {
        echo <<< EOL
<form action="" method="post">

    <h2>データ一覧</h2>
    <input type='submit' name='submit[regist]' class='button-primary' value='新規登録' />
    <input type='submit' name='submit[regist_file]' class='button-primary' value='新規登録(ファイルアップロード)' />

    <div class="wrap">

    <table class="wp-list-table widefat striped posts">
        <tr>
            <th nowrap>ID</th>
            <th nowrap>名前</th>
            <th nowrap>テキスト</th>
            <th nowrap>チェック</th>
            <th nowrap>ラジオ</th>
            <th nowrap>セレクト</th>
            <th nowrap>テキストエリア</th>
            <th nowrap>登録日時</th>
            <th nowrap>詳細</th>
            <th nowrap>編集</th>
        </tr>
EOL;

以下、省略します…

すると次のような画面になります。

続いて、ボタンを押下した際の動作を決める関数に、ファイルアップロード用画面と、アップロードボタンを押された際のメソッドを追加します。

function sample_plugin()
{
    if (isset($_REQUEST["submit"]["detail"])) {
        //他の処理は記述を省略します…

    } else if (isset($_REQUEST["submit"]["regist_file"])) {
        //ファイルアップロード用画面
        self::regist_file();
    } else if (isset($_REQUEST["submit"]["regist_file_up"])) {
        //ファイルアップロード処理
        self::regist_file_up();

    } else {
        self::disp();
    }
}

次に、画面上の「新規登録(ファイルアップロード)」ボタンを押した時の処理を書きます。

function regist_file($error_message_flg = null)
{
    echo <<< EOL
<h2>ファイルアップロード</h2>
<div class="wrap">
<div class="wrap">
<table class="wp-list-table widefat striped posts">
    <tr>
        <td>ファイルアップロード</td>
        <td>
            <form method="post" action="" enctype="multipart/form-data">
                CSVを選択してアップロードボタンを押してください<br />
                <input type="file" name="upfilename" />
                <input type="submit" value="アップロード">
                <input type="hidden" name="submit[regist_file_up]" value="on">
            </form>

        </td>
    </tr>
</table>
</div>
<form action="" method="post">
    <input type='submit' name='submit[file_upload]' class='button-primary' value='戻る' />
    <input type="hidden" name="form_id" value="{$form_id}">
    <input type="hidden" name="create_date" value="{$create_date}">
</form>
</div>
EOL;

}

今はデザインやレイアウトについては、割愛して書いています。
画面はこのようになります。

画面上から、ファイルを選択してアップロードボタンを押した後の処理は次のように書きました。

function regist_file_up()
{
    //CSVファイルがアップロードされた場合
    if (is_uploaded_file($_FILES["upfilename"]["tmp_name"])) {
        $upload_dir = wp_upload_dir();
        $upload_file_name = $upload_dir['basedir'] . "/" . $_FILES["upfilename"]["name"];
        if (move_uploaded_file($_FILES["upfilename"]["tmp_name"], $upload_file_name)) {
            chmod($upload_file_name, 0777);
        }
        $message = "ファイルをアップロードいたしました";
    } else {
        $message = "ファイルのアップロードが失敗しました";
    }

    //完了メッセージの出力
    echo <<< EOL
<h2>ファイルアップロード完了</h2>
<form action="" method="post">
<div class="wrap">
    {$message}
</div>
<input type='submit' name='submit[]' class='button-primary' value='戻る' />
</form>
EOL;

}

書き方は一般的なファイルアップロードによる処理と、変わらないですが、「wp_upload_dir();」というwordpressが用意している関数を使っている点がポイントになります。

この関数をコールし、「$upload_dir[‘basedir’]」という値をとることにより、wordpressの「uploads」ディレクトリまでのフルパスを参照できます。

そうすることで、uploadsディレクトリ直下にファイルをアップロードすることができています。

完了後は、次のような画面になります。

これで、ファイルをアップロードが完了します。
工夫や改善の余地はありますが、基本的な流れはできているので、あとはどのように応用するかになります。

管理画面側に、wordpressに搭載されているメディアアップローダを組み込んでみます。

今回、非常に参考にしたサイトはこちらのサイト様になります。

そもそも管理画面にファイルをアップロードする機能はphp標準のファイルアップロードの処理を書くことでも実装が可能です。
ただ、その場合はアップロード先ディレクトリをどうするか、仕様を決めておかないといけない為、配慮すべき項目が多くなりがちです。

そこでメディアアップローダを使うことで、アップロードとファイル保存先についてはある程度wordpressまかせにすることができます。

以下、実装手順を記載します。

まず、__construct()等に、必要となるjavascript関連のファイルを読み込みます。

wp_enqueue_script('media-upload');
wp_enqueue_script('thickbox');

次に、スタイルシート関連のファイルも読み込みます。これは同じくコンストラクタ内で問題ありませんが、独自にスタイルシート読み込み用に関数を分けておいてもいいかもしれません。

wp_enqueue_style('thickbox');

続いて、登録画面に対して、ファイルアップロードの為のフォームを記載します。(ここは上記参考サイト様の書き方を引用させていただきました)

<input type="text" id="my_media_1" name="my_media_1" value="" />
<a class="media-upload" href="JavaScript:void(0);" rel="my_media_1">ファイル選択</a>

そして、フォーム内の「ファイル選択」リンクを押下した時に、
メディアアップロードのダイアログを立ち上げる為に、以下のjavascriptを記載します。

<script type="text/javascript">
jQuery("document").ready(function(){
    jQuery(".media-upload").each(function(){
        var rel = jQuery(this).attr("rel");
        jQuery(this).click(function(){
            window.send_to_editor = function(html) {
                imgurl = jQuery("img", html).attr("src");
                jQuery("#"+rel).val(imgurl);
                tb_remove();
            }   
            formfield = jQuery("#"+rel).attr("name");
            tb_show(null, "media-upload.php?post_id=0&type=image&TB_iframe=true");
            return false;
        });
    });
});
</script>

という記載をフォームが表示される画面内のHTMLタグのどこかに記載します。

以上の記述をすることで、フォーム画面からメディアアップロードの画面を出し、そこでファイルを選択して、URL等をフォームにセットすることができます。

以下、これまでに作成してきたサンプルプラグインの「新規登録」画面に対して、ファイルアップロードの項目を追加してみたので、そのキャプチャを貼ります。

赤枠部分が実際に操作をしてみて、ファイルのアップロード(例ではアップロード済みのファイルを選択しました)、ファイル名取得、フォーム項目への設置、という一連の動きになっています。

①新規登録画面へ

②登録画面から「ファイル選択」をクリック

③既にアップロード済みのファイルを選択

④該当のファイル(例では「00.png」を選択)し、詳細画面を表示。その後「ファイルのURL」を取得するボタンを押す

⑤ファイル名が取得できます

⑥同画面の下にある「投稿に挿入」ボタンを押して、元の新規登録フォームへ戻ると、ファイル名がセットされています。

ページャの見直し

前回のページャを設置した記事をおさらいを含めて、見直してみます。

前回投稿した記事http://propansystem.net/blog/?p=1022では、登録データ数の無関係にページャ表示をしていました。

この場合、1画面内に10記事のデータ数を超えている場合は問題ありませんが、10記事以内のデータの場合にもページャが1ページ分のみ表示されてしまいます。

ページャをクリックしても何も起きず、ページャを表示していまうことで余計に操作しずらくなります。

そこで、データ一覧を出力する箇所のページャ表示部分に件数制限のロジックを入れて、10件未満の場合にはページャを表示しないようにします。

データ一覧を表示する関数部分を抜粋します。

	function disp()
	{
		//データ一覧
		echo <<< EOL
<form action="" method="post">
<h2>データ一覧</h2>
<input type='submit' name='submit[regist]' class='button-primary' value='新規登録' />
<div class="wrap">
<table class="wp-list-table widefat striped posts">
	<tr>
		<th nowrap>ID</th>
		<th nowrap>名前</th>
		<th nowrap>テキスト</th>
		<th nowrap>チェック</th>
		<th nowrap>ラジオ</th>
		<th nowrap>セレクト</th>
		<th nowrap>テキストエリア</th>
		<th nowrap>登録日時</th>
		<th nowrap>詳細</th>
		<th nowrap>編集</th>
	</tr>
EOL;

		//現在ページ取得
		$pageid = filter_input(INPUT_GET, 'pageid');

		//1ページあたりの件数
		$limit = 10;

		//DBオブジェクトを用意
		global $wpdb;

		//全件数取得
		$tbl_name = $wpdb->prefix . 'sample_mst';
		$sql = "SELECT count(*) AS CNT FROM {$tbl_name}";
		$rows = $wpdb->get_results($sql);
		$recordcount = $rows[0]->CNT;

		$offset = $pageid * $limit;

		//offset と limitによる画面表示用のデータ取得
		$sql = "SELECT * FROM {$tbl_name} ORDER BY id limit {$offset}, {$limit};";

		//通常の取得方法(SQL実行結果を、オブジェクトとして取得)
		$rows = $wpdb->get_results($sql);

		foreach($rows as $row) {
			echo "<tr>";
			echo "<td>" . $row->id . "</td>";
			echo "<td>" . $row->sample_name . "</td>";
			echo "<td>" . $row->sample_text . "</td>";
			echo "<td>" . $row->sample_check . "</td>";
			echo "<td>" . $row->sample_radio . "</td>";
			echo "<td>" . $row->sample_select . "</td>";
			echo "<td>" . $row->sample_textarea . "</td>";
			echo "<td>" . $row->create_date . "</td>";
			echo "<td>";
			echo "<input type='submit' name='submit[detail][" . $row->id . "]'";
			echo " class='button-primary' value='詳細' />";
			echo "</td>";
			echo "<td>";
			echo "<input type='submit' name='submit[edit][" . $row->id . "]'";
			echo " class='button-primary' value='編集' />";
			echo "</td>";
			echo "</tr>";
		}
		echo "</table>";
		echo "</div>";
		echo "</form>";

		//データ数が1画面あたりの記事数を超える場合のみ、ページャを表示する
		if ($recordcount > $limit) {
			$args = array(
				'label' => __('Per Page'),
				'default' => 10,
				'option' => 'disp'
			);
			$page_html = self::pagination($recordcount);

			//ページ部分の表示
			echo "<div class='admin_pagination'>";
			echo "<ul>";
			foreach ($page_html as $key => $value) {
				echo "<li>" . $value . "</li>";
			}
			echo "</ul>";
		}

	}

関数の最後で「if ($recordcount > $limit) {」という分岐を行い、
10件に満たない場合の制御をしています。

こうすることにより、データ数が少ない場合は、以下のような表示になります。

画面表示の書き方はもっとシンプルで、わかりやすい書き方はあると思いますが、今は不恰好ですが動作しているので次に進めていきます。

wordpress流の書き方については、今後の研究課題にして追求していく予定です。

クイックリターン関数について、調べてみます。
下記のようなコードを例にします。

add_filter("test_filter", "sample_func");
function sample_func() {
    //何らかの処理
    return true;
}

上記のコードは「test_filter」としてフィルターフックを指定し、sample_func関数をコールバックしています。

sample_func関数内で何らかの処理を行う関数の場合、次のような戻り値の時に簡略化して書くことができます。

「true」「false」「array()」(空の配列を返す)「””」「null」「0」

上記の戻り値の場合、

function sample_func() {
    //何らかの処理
    return true;
}

の関数定義を書かずに、

add_filter("test_filter", "__return_true");

のように一行で書くことできます。
下記のそれぞれのケースでは、
「false」「array()」(空の配列を返す)「””」「null」「0」
次のように書けます。

//false
add_filter("test_filter", "__return_false");
//array()
add_filter("test_filter", "__return_empty_array");
//""
add_filter("test_filter", "__return_empty_string");
//null
add_filter("test_filter", "__return_null");
//0
add_filter("test_filter", "__return_zero");

実際にフィルターを使う時に試してみるほうが良さそうです。

前の投稿ではプラグインを有効化した時に実行される関数についてでしたが、今回はプラグインを無効化した時に実行される関数について調べてみます。

無効化する時に実行される関数は以下になります。

register_deactivation_hook($file, $callback);

第一引数は、有効化した時の関数と同じく、実行されるプログラムのファイル名を指定します。
「__FILE__」等と指定しても問題なく動作します。

第二引数は無効化した時に実行されるコールバック関数を指定します。

例として、以下のように書きます。

register_deactivation_hook(__FILE__, 'test_de_action');

function test_de_action() {
    //ここで何らかの処理
}

関数側がクラスを使っている場合は、次のように書きます。

register_activation_hook(__FILE__, array('test_class', 'test_de_action');
 
class test_class {
    function test_de_action() {
        //ここで何らかの処理
    }
}

有効化と同じように書けるので、有効化の処理が問題なく動作すれば、そのまま無効化も同じように書くことができます。

プラグインの機能として、プラグインをインストールした後に、「有効化」を行うタイミングの時に1度だけ実行される関数が用意されています。

以前、プラグインを作成した際、過去のブログ(http://propanmode.net/blog/?p=884)でも取り上げていましたが、もう少し深く調べてみます。

プラグインの有効化のタイミングで実行される関数は、以下のようになります。

register_activation_hook($file, $callback);

第一引数はプラグインのメインPHPファイルのパスを、
第二引数にはプラグインを有効化した時に実行されるコールバック関数を指定します。

例として、次のようになります。

register_activation_hook(__FILE__, 'test_action');

function test_action() {
    //ここで何らかの処理
}

関数側がクラスを使っている場合は、第二引数の書き方が次のように変わります。

register_activation_hook(__FILE__, array('test_class', 'test_action');

class test_class {
    function test_action() {
        //ここで何らかの処理
    }
}

実際にプラグイン作成時に書いた処理なので、動作検証については既に完了しています。
あとは処理の中で何をどうプログラムするのかで様々な操作をすることが可能になるので、そこは設計次第になります。

アクションフックにアクションを登録する方法は以下になります。

※wordpressの公式ドキュメントからの抜粋になりますが、若干説明を簡易にしています。

add_action(アクションを適用するフック名, コールバック関数, 優先順位, フックした関数が受け入れられる引数の数);

この登録したアクションの中身は以下のように記述します。
※これもwordpressの公式ドキュメントから参照したコードです。

function email_friends( $post_ID )  {
   $friends = 'bob@example.org, susie@example.org';
   wp_mail( $friends, "sally's blog updated", 'I just put something on my blog: http://blog.example.com' );

   return $post_ID;
}
add_action( 'publish_post', 'email_friends' );

上記のコードは「ブログを投稿しときに、メール通知を行う」という動作のようです。

add_actionの第一引数で「アクションを呼ぶきっかけとなる動作」を決定しています。
この第一引数には、様々な操作を設定できるようで、以下の公式ドキュメントにまとめられています。
http://wpdocs.osdn.jp/%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3_API/%E3%82%A2%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%95%E3%83%83%E3%82%AF%E4%B8%80%E8%A6%A7

上記URLを見ると「一般的リクエスト中に実行されるアクション」や「管理画面リクエスト中に実行されるアクション」等といったアクションのきっかけがまとめれています。

この情報を使って第一引数を決定し、特定の動作を行う関数を用意する。
というような実装の流れになると思われます。(実際の実装は今後の課題予定とします)

アクションフックについて

do_action()が実行されている場所をアクションフックと呼びます。

アクションフックはフィルターフックと似ています。
どちらもフック(きっかけ)があった場合に処理が動きます。

アクションフックは、管理画面などで、投稿記事の公開、テーマ変更、などが行われた際に始動されます。

また、フィルターフックについてはwordpressのサイト側を表示する際に、特定の処理を通して表示を変更したい場合、等に利用されます。

アクションについて

アクションは特定のイベントが発生した際に実行される処理を言います。
例えば、wp_headアクションはよく利用されるアクションです。

テンプレート内でwp_headが呼び出されたら、cssやjsの読み込みを一括して行う。といった処理で利用される例があります。

apply_filters()にフィルターを追加するにはadd_filter()関数を使います。

これは実際に書いてみないと分からないので、簡単なサンプルプログラムを作ります。

前回の投稿で、簡単なサンプルを作りました。
それをおさらいしてみます。

フィルターフックを設置する
function sample_func1() {
    return apply_filters("sample_filter", "hoge");
}

//「sample_filter」フックに対して、コールバック関数(sample_call)を指定する
add_filter("sample_filter", "sample_call");
 
//コールバック関数
function sample_call($value) {
    return "fuga";
}

applry_filtersはフィルターフックを設置するための関数です。
第一引数がフック名、第二引数がコールバック関数への引数になります。

フィルターフックについて

フィルターの使い方について、学びます。

フィルターフックについて

wordpressはHTMLの出力や、各種設定、環境変数、フォーム入力値などは、apply_filters()という関数を経由します。

例えば、ある関数を定義して、それをフィルターフックを設置する場合は、次のように書きます。

function sample_func1() {
	return "test";
}

この関数をフィルターフックを設置します。

function sample_func1() {
	return apply_filters("sample_filter", "hoge");
}

上記のフィルターフックを、プラグインやテーマのfunctions.phpで次のように適用します。

add_filter("sample_filter", "sample_call");

function sample_call($value) {
	return "fuga";
}

実際にこのフィルターフックを利用したプログラムを作成してみます。

これまでの管理画面の作りは、ほぼphpのみで実装してきました。

次にこの管理画面にjavascirpt(jquery)を動作させるように設定してみます。

まず、プラグインフォルダの中に、jsファイルを設置する為のディレクトリを作成します。

/ワードプレス設置ディレクトリ/wp-content/plugins/SamplePlugin1

上記のディレクトリに対し、jsディレクトリを作成します。

/ワードプレス設置ディレクトリ/wp-content/plugins/SamplePlugin1/js/

次に、そのディレクトリ内に、javascript用のファイルを設置します。

/ワードプレス設置ディレクトリ/wp-content/plugins/SamplePlugin1/js/sample1_script.js

jsの中は、jqueryが使用できるので、以下のようなサンプルコードを書きます。

(function($){
    alert("hello jquery !");
})(jQuery);

次に、プラグイン本体のphpのコンストラクタの中に、以下の読み込み命令文を書きます。

wp_register_script('sample1js', plugins_url( './js/sample1_script.js', __FILE__ ));
wp_enqueue_script('sample1js');

こうすることで、プラグインの画面にアクセスした時にjsがロードされます。
例では、アラートを表示するだけのシンプルなjsですが、画面にアクセスすると以下のようになります。

アラート表示だけのプログラムなので、あまり意味がないですが、jsが動作することを確認できました。

登録画面を追加する

前回までのソースコードを元に、新規登録画面の一連の動きを書きます。

	/**
	 * 登録
	 */
	function regist($error_message_flg = null)
	{
		if ($error_message_flg == false) {
			$sample_name = esc_attr($_REQUEST["sample_name"]);
		}

		if (isset($_REQUEST["form_id"])) {
			//確認画面の「戻る」ボタンから遷移してきた場合
			$form_id = esc_attr($_REQUEST["form_id"]);

			$sample_name = esc_attr($_REQUEST["sample_name"]);
			$sample_text = esc_attr($_REQUEST["sample_text"]);
			$sample_check = $_REQUEST["sample_check"];
			$sample_radio = esc_attr($_REQUEST["sample_radio"]);
			$sample_select = esc_attr($_REQUEST["sample_select"]);
			$sample_textarea = esc_attr($_REQUEST["sample_textarea"]);

			//チェックボックスの判定
			foreach ($sample_check as $key => $value) {
				$sample_check_checked[$value] = "checked";
			}
			
			//ラジオボタンの判定
			for ($i=0; $i<3; $i++) {
				if ($sample_radio == $i) {
					$sample_radio_checked[$i] = "checked";
				}
			}
			
			//セレクトボックスの判定
			$sample_select_array = array("a", "b", "c", "d", "e");
			foreach ($sample_select_array as $key => $value) {
				if ($sample_select == $value) {
					$sample_select_selected[$key] = "selected";
				}
			}

			$create_date = esc_attr($_REQUEST["create_date"]);
		} else {
			
			//一覧画面から「編集」ボタンを押下した場合
			
			//押されたボタンのIDを取得する
			if (array_search("編集", $_REQUEST["submit"]["edit"])) {
				$form_id = array_search("編集", $_REQUEST["submit"]["edit"]);
			}

			global $wpdb;
			$tbl_name = $wpdb->prefix . 'sample_mst';
			$sql = "SELECT * FROM {$tbl_name} WHERE id = %d;";
			$prepared = $wpdb->prepare($sql, $form_id);
			$rows = $wpdb->get_results($prepared, ARRAY_A);

			$sample_name = $rows[0]["sample_name"];
			$sample_text  = $rows[0]["sample_text"];
			$sample_check  = $rows[0]["sample_check"];
			$sample_radio  = $rows[0]["sample_radio"];
			$sample_select  = $rows[0]["sample_select"];
			$sample_textarea = $rows[0]["sample_textarea"];

			$sample_check = explode(",", $sample_check);

			//チェックボックスの判定
			foreach ($sample_check as $key => $value) {
				$sample_check_checked[$value] = "checked";
			}
			
			//ラジオボタンの判定
			for ($i=0; $i<3; $i++) {
				if ($sample_radio == $i) {
					$sample_radio_checked[$i] = "checked";
				}
			}
			
			//セレクトボックスの判定
			$sample_select_array = array("a", "b", "c", "d", "e");
			foreach ($sample_select_array as $key => $value) {
				if ($sample_select == $value) {
					$sample_select_selected[$key] = "selected";
				}
			}

			$create_date = $rows[0]["create_date"];

		}

		echo <<< EOL
<form action="" method="post">
<h2>データ登録</h2>
EOL;

		if (strlen($error_message_flg)) {
			echo "<div class='updated fade'><p><strong>";
			echo _e('NAMEを入力してください');
			echo "</strong></p></div>";
		}

		echo <<< EOL

<div class="wrap">

<form action="" method="post">
	<h2>データ編集</h2>

	<div class="wrap">

	<table class="wp-list-table widefat striped posts">
		<tr>
			<td>ID</td>
			<td>{$form_id}</td>
		</tr>
		<tr>
			<td>NAME</td>
			<td>
				<input type="text" name="sample_name" value="{$sample_name}">
			</td>
		</tr>

		<tr>
			<td>テキスト</td>
			<td>
				<input type="text" name="sample_text" value="{$sample_text}">
			</td>
		</tr>
		<tr>
			<td>チェックボックス</td>
			<td>
				チェック値1<input type="checkbox" name="sample_check[]" value="0" {$sample_check_checked[0]}>
				チェック値2<input type="checkbox" name="sample_check[]" value="1" {$sample_check_checked[1]}>
				チェック値3<input type="checkbox" name="sample_check[]" value="2" {$sample_check_checked[2]}>
			</td>
		</tr>
		<tr>
			<td>ラジオボタン</td>
			<td>
				ラジオ値1<input type="radio" name="sample_radio" value="0" {$sample_radio_checked[0]}>
				ラジオ値2<input type="radio" name="sample_radio" value="1" {$sample_radio_checked[1]}>
				ラジオ値3<input type="radio" name="sample_radio" value="2" {$sample_radio_checked[2]}>
			</td>
		</tr>
		<tr>
			<td>セレクトボックス</td>
			<td>
				<select name="sample_select">
					<option value="a" {$sample_select_selected[0]}>選択a</option>
					<option value="b" {$sample_select_selected[1]}>選択b</option>
					<option value="c" {$sample_select_selected[2]}>選択c</option>
					<option value="d" {$sample_select_selected[3]}>選択d</option>
					<option value="e" {$sample_select_selected[4]}>選択e</option>
				</select>
			</td>
		</tr>
		<tr>
			<td>テキストエリア</td>
			<td>
				<textarea name="sample_textarea" cols="30" rows="5">{$sample_textarea}</textarea>
			</td>
		</tr>

		<tr>
			<td>登録日時</td>
			<td>{$create_date}</td>
		</tr>
	</table>

	<input type='submit' name='submit[regist_check]' class='button-primary' value='登録内容を確認する' />
	<input type='submit' name='submit[]' class='button-primary' value='戻る' />

	<input type="hidden" name="form_id" value="{$form_id}">
	<input type="hidden" name="create_date" value="{$create_date}">

	</div>

</form>

EOL;
	}

	/**
	 * 登録確認
	 */
	function regist_check()
	{
		if (!strlen($_REQUEST["sample_name"])) {
			self::regist(false);
			return;
		}
		
		$sample_name = esc_attr($_REQUEST["sample_name"]);

		$sample_name = esc_attr($_REQUEST["sample_name"]);
		$sample_text = esc_attr($_REQUEST["sample_text"]);
		$sample_check = $_REQUEST["sample_check"];
		$sample_radio = esc_attr($_REQUEST["sample_radio"]);
		$sample_select = esc_attr($_REQUEST["sample_select"]);
		$sample_textarea = esc_attr($_REQUEST["sample_textarea"]);

		//チェックボックスの値を処理
		if (is_array($_REQUEST["sample_check"])) {
			foreach ($_REQUEST["sample_check"] as $key => $value) {
				$disp_checkbox .= "チェック値" . $value . "<br />";
				$hidden_checkbox .= '<input type="hidden" name="sample_check[]" value="' . $value . '">';
			}
		}

		//テキストエリア整形(表示用)
		$sample_textarea_disp = nl2br($sample_textarea);

		//データ一覧
		echo <<< EOL
<form action="" method="post">
	<h2>データ編集確認</h2>

	<div class="wrap">

	    <table class="wp-list-table widefat striped posts">
			<tr> 
				<td>ID</td>
				<td>{$form_id}</td>
			</tr>
			<tr> 
				<td>NAME</td>
				<td>{$sample_name}</td>
			</tr>
			<tr> 
				<td>テキスト</td>
				<td>{$sample_text}</td>
			</tr>
			<tr> 
				<td>チェックボックス</td>
				<td>
					{$disp_checkbox}
				</td>
			</tr>
			<tr> 
				<td>ラジオボタン</td>
				<td>{$sample_radio}</td>
			</tr>
			<tr> 
				<td>セレクトボックス</td>
				<td>{$sample_select}</td>
			</tr>
			<tr> 
				<td>テキストエリア</td>
				<td>{$sample_textarea_disp}</td>
			</tr>
		</table>

	<input type="hidden" name="form_id" value="{$form_id}">

	<input type="hidden" name="sample_name" value="{$sample_name}">
	<input type="hidden" name="sample_text" value="{$sample_text}">
	{$hidden_checkbox}
	<input type="hidden" name="sample_radio" value="{$sample_radio}">
	<input type="hidden" name="sample_select" value="{$sample_select}">
	<input type="hidden" name="sample_textarea" value="{$sample_textarea}">

	<input type="hidden" name="create_date" value="{$create_date}">

	</div>

	<input type='submit' name='submit[regist_exec]' class='button-primary' value='登録する' />
	<input type='submit' name='submit[regist]' class='button-primary' value='戻る' />

</form>
EOL;

	}

	/**
	 * 登録実行
	 */
	function regist_exec()
	{
		global $wpdb;

		$sample_name = esc_attr($_REQUEST["sample_name"]);
		$sample_text = esc_attr($_REQUEST["sample_text"]);
		$sample_radio = esc_attr($_REQUEST["sample_radio"]);
		$sample_select = esc_attr($_REQUEST["sample_select"]);
		$sample_textarea = esc_attr($_REQUEST["sample_textarea"]);

		//チェックボックスの値を処理
		if (is_array($_REQUEST["sample_check"])) {
			foreach ($_REQUEST["sample_check"] as $key => $value) {
				$sample_check .= $value . ",";
			}
		}

		//投稿を登録
		$table_name = $wpdb->prefix . 'sample_mst';
		$result = $wpdb->insert(
			$table_name,
			array(
				'sample_name' => $sample_name,
				'sample_text' => $sample_text,
				'sample_check' => $sample_check,
				'sample_radio' => $sample_radio,
				'sample_select' => $sample_select,
				'sample_textarea' => $sample_textarea,
				'create_date' => current_time('mysql')
			)
		);

		//データ一覧
		echo <<< EOL
<form action="" method="post">
<h2>データ登録</h2>
<div class='updated fade'><p><strong>
EOL;

		echo _e('登録が完了しました');

		echo <<<EOL
</strong></p></div>
<input type='submit' name='submit[]' class='button-primary' value='戻る' />
EOL;
		echo "</form>";
	}

更新系ですので、修正の処理を同じような流れになります。
登録フォームがあり、確認画面があり、完了メッセージ画面があります。

詳細画面の項目を追加する

これまでに追加した項目を編集画面で自由に編集ができるようになりました。

次は詳細画面の項目を追加し、表示項目を合わせようと思います。
改修したソースは以下のようになります。


/**
 * 詳細表示
 */
function detail()
{
	//押されたボタンのIDを取得する
	if (array_search("詳細", $_REQUEST["submit"]["detail"])) {
		$form_id = array_search("詳細", $_REQUEST["submit"]["detail"]);
	}

	//データ一覧
	echo <<< EOL
<form action="" method="post">
<h2>データ詳細</h2>

EOL;

	global $wpdb;

	$tbl_name = $wpdb->prefix . 'sample_mst';
	$sql = "SELECT * FROM {$tbl_name} WHERE id = %d;";
	$prepared = $wpdb->prepare($sql, $form_id);
	$rows = $wpdb->get_results($prepared, ARRAY_A);

	$sample_name = $rows[0]["sample_name"];
	$sample_text  = $rows[0]["sample_text"];
	$sample_check  = $rows[0]["sample_check"];
	$sample_radio  = $rows[0]["sample_radio"];
	$sample_select  = $rows[0]["sample_select"];
	$sample_textarea = $rows[0]["sample_textarea"];

	$create_date = $rows[0]["create_date"];

	echo <<<EOL

<div class="wrap">

<table class="wp-list-table widefat striped posts">
	<tr>
		<td>ID</td>
		<td>{$form_id}</td>
	</tr>

	<tr>
		<td>NAME</td>
		<td>{$sample_name}</td>
	</tr>

	<tr>
		<td>テキスト</td>
		<td>{$sample_text}</td>
	</tr>
	<tr>
		<td>チェック</td>
		<td>{$sample_check}</td>
	</tr>
	<tr>
		<td>ラジオ</td>
		<td>{$sample_radio}</td>
	</tr>
	<tr>
		<td>セレクト</td>
		<td>{$sample_select}</td>
	</tr>
	<tr>
		<td>テキストエリア</td>
		<td>{$sample_textarea}</td>
	</tr>

	<tr>
		<td>登録日時</td>
		<td>{$create_date}</td>
	</tr>
</table>

</div>

<input type="hidden" name="form_id" value="{$form_id}">

<input type='submit' name='submit[delete_check]' class='button-primary' value='削除確認する' />
<input type='submit' name='submit[]' class='button-primary' value='戻る' />
EOL;
	echo "</form>";
}

実行した画面は以下のようになります。

DBの内容をそのまま表示しているので、チェックボックス、ラジオボタン、セレクトボックスの箇所は工夫が必要になります。
何を出力させたいのか、を明確にして形づくるのがよいです。

編集ボタン押下時の処理を書く

前回までは、一覧画面から該当のデータを選択し、編集フォームにDBの値をセットし、その値を編集して確認画面を出力するところまで実装しました。

次は、編集確認画面から、編集ボタンを押下し、編集処理をするプログラムを書きます。

編集実行時のプログラムは以下のようになります。

/**
 * 編集実行
 */
function edit_exec()
{
	global $wpdb;

	$form_id = esc_attr($_REQUEST["form_id"]);

	$sample_name = esc_attr($_REQUEST["sample_name"]);
	$sample_text = esc_attr($_REQUEST["sample_text"]);
	$sample_radio = esc_attr($_REQUEST["sample_radio"]);
	$sample_select = esc_attr($_REQUEST["sample_select"]);
	$sample_textarea = esc_attr($_REQUEST["sample_textarea"]);
	$update_date = date("Y-m-d H:i:s");

	//チェックボックスの値を処理
	if (is_array($_REQUEST["sample_check"])) {
		foreach ($_REQUEST["sample_check"] as $key => $value) {
			$disp_checkbox .= "チェック値" . $value . "<br />";
			$sample_check .= $value . ',';
		}
	}

	//投稿を更新
	$tbl_name = $wpdb->prefix . 'sample_mst';
	$result = $wpdb->update(
		$tbl_name,
		array(
			'sample_name' => $sample_name,
			'sample_text' => $sample_text,
			'sample_check' => $sample_check,
			'sample_radio' => $sample_radio,
			'sample_select' => $sample_select,
			'sample_textarea' => $sample_textarea,
			'update_date' => $update_date,
		),
		array('id' => $form_id,),
		array(
			'%s',
			'%s',
			'%s',
			'%s',
			'%s',
			'%s'
		),
		array('%d')
	);

	//データ一覧
	echo <<< EOL
<form action="" method="post">
	<h2>データ修正</h2>
	<div class='updated fade'><p><strong>
EOL;
	echo _e('更新が完了しました');
	echo <<<EOL
</strong></p></div>
<input type='submit' name='submit[]' class='button-primary' value='戻る' />
</form>
EOL;
}

この処理を実行すると、DB内には、編集画面で入力された値が格納されます。

$wpdbの使い方は、さらに研究する必要がありますが、今のところ上記の書き方で更新されるので、この書き方で進めます。

また、前回までに書いた編集画面の値のセットの仕方がいまいちな部分があったので、それも合わせて変更しました。

/**
 * 修正
 */
function edit()
{
	if (isset($_REQUEST["form_id"])) {
		//確認画面の「戻る」ボタンから遷移してきた場合
		$form_id = esc_attr($_REQUEST["form_id"]);

		$sample_name = esc_attr($_REQUEST["sample_name"]);
		$sample_text = esc_attr($_REQUEST["sample_text"]);
		$sample_check = $_REQUEST["sample_check"];
		$sample_radio = esc_attr($_REQUEST["sample_radio"]);
		$sample_select = esc_attr($_REQUEST["sample_select"]);
		$sample_textarea = esc_attr($_REQUEST["sample_textarea"]);

		//チェックボックスの判定
		foreach ($sample_check as $key => $value) {
			$sample_check_checked[$value] = "checked";
		}
		
		//ラジオボタンの判定
		for ($i=0; $i<3; $i++) {
			if ($sample_radio == $i) {
				$sample_radio_checked[$i] = "checked";
			}
		}
		
		//セレクトボックスの判定
		$sample_select_array = array("a", "b", "c", "d", "e");
		foreach ($sample_select_array as $key => $value) {
			if ($sample_select == $value) {
				$sample_select_selected[$key] = "selected";
			}
		}

		$create_date = esc_attr($_REQUEST["create_date"]);
	} else {
		
		//一覧画面から「編集」ボタンを押下した場合
		
		//押されたボタンのIDを取得する
		if (array_search("編集", $_REQUEST["submit"]["edit"])) {
			$form_id = array_search("編集", $_REQUEST["submit"]["edit"]);
		}

		global $wpdb;
		$tbl_name = $wpdb->prefix . 'sample_mst';
		$sql = "SELECT * FROM {$tbl_name} WHERE id = %d;";
		$prepared = $wpdb->prepare($sql, $form_id);
		$rows = $wpdb->get_results($prepared, ARRAY_A);

		$sample_name = $rows[0]["sample_name"];
		$sample_text  = $rows[0]["sample_text"];
		$sample_check  = $rows[0]["sample_check"];
		$sample_radio  = $rows[0]["sample_radio"];
		$sample_select  = $rows[0]["sample_select"];
		$sample_textarea = $rows[0]["sample_textarea"];

		$sample_check = explode(",", $sample_check);

		//チェックボックスの判定
		foreach ($sample_check as $key => $value) {
			$sample_check_checked[$value] = "checked";
		}
		
		//ラジオボタンの判定
		for ($i=0; $i<3; $i++) {
			if ($sample_radio == $i) {
				$sample_radio_checked[$i] = "checked";
			}
		}
		
		//セレクトボックスの判定
		$sample_select_array = array("a", "b", "c", "d", "e");
		foreach ($sample_select_array as $key => $value) {
			if ($sample_select == $value) {
				$sample_select_selected[$key] = "selected";
			}
		}

		$create_date = $rows[0]["create_date"];
	}

	//データ一覧
	echo <<< EOL
<form action="" method="post">
	<h2>データ編集</h2>

	<div class="wrap">

	<table class="wp-list-table widefat striped posts">
		<tr>
			<td>ID</td>
			<td>{$form_id}</td>
		</tr>
		<tr>
			<td>NAME</td>
			<td>
				<input type="text" name="sample_name" value="{$sample_name}">
			</td>
		</tr>

		<tr>
			<td>テキスト</td>
			<td>
				<input type="text" name="sample_text" value="{$sample_text}">
			</td>
		</tr>
		<tr>
			<td>チェックボックス</td>
			<td>
				チェック値1<input type="checkbox" name="sample_check[]" value="1" {$sample_check_checked[0]}>
				チェック値2<input type="checkbox" name="sample_check[]" value="2" {$sample_check_checked[1]}>
				チェック値3<input type="checkbox" name="sample_check[]" value="3" {$sample_check_checked[2]}>
			</td>
		</tr>
		<tr>
			<td>ラジオボタン</td>
			<td>
				ラジオ値1<input type="radio" name="sample_radio" value="1" {$sample_radio_checked[0]}>
				ラジオ値2<input type="radio" name="sample_radio" value="2" {$sample_radio_checked[1]}>
				ラジオ値3<input type="radio" name="sample_radio" value="3" {$sample_radio_checked[2]}>
			</td>
		</tr>
		<tr>
			<td>セレクトボックス</td>
			<td>
				<select name="sample_select">
					<option value="a" {$sample_select_selected[0]}>選択a</option>
					<option value="b" {$sample_select_selected[1]}>選択b</option>
					<option value="c" {$sample_select_selected[2]}>選択c</option>
					<option value="d" {$sample_select_selected[3]}>選択d</option>
					<option value="e" {$sample_select_selected[4]}>選択e</option>
				</select>
			</td>
		</tr>
		<tr>
			<td>テキストエリア</td>
			<td>
				<textarea name="sample_textarea" cols="30" rows="5">{$sample_textarea}</textarea>
			</td>
		</tr>

		<tr>
			<td>登録日時</td>
			<td>{$create_date}</td>
		</tr>
	</table>

	<input type='submit' name='submit[edit_check]' class='button-primary' value='編集内容を確認する' />
	<input type='submit' name='submit[]' class='button-primary' value='戻る' />

	<input type="hidden" name="form_id" value="{$form_id}">
	<input type="hidden" name="create_date" value="{$create_date}">

	</div>

</form>
EOL;
}

変更した箇所は、一覧画面から該当のデータを選択した際、チェックボックス、ラジオボタン、セレクトボックスのそれぞれの値がうまくセットされなかったので、次のように記述し、処理を追加しました。

//チェックボックスの判定
foreach ($sample_check as $key => $value) {
	if ($value != "") {
		$sample_check_checked[$key] = "checked";
	}
}

//ラジオボタンの判定
for ($i=0; $i<3; $i++) {
	if ($sample_radio == $i) {
		$sample_radio_checked[$i] = "checked";
	}
}

//セレクトボックスの判定
$sample_select_array = array("a", "b", "c", "d", "e");
foreach ($sample_select_array as $key => $value) {
	if ($sample_select == $value) {
		$sample_select_selected[$key] = "selected";
	}
}

こうすることにより、既存のデータをフォームにセットすることができるようになります。
フォーム関連の書き方はこの限りではないので、もっとうまい書き方や、効率的な書き方、ライブラリを使った書き方など、数多くの方法があると思われます。
そこはおいおいの研究課題にします。

編集の一連の動作は、次のような画面になります。

■編集一覧

■編集ボタン押下後

■値の変更

■編集確認画面

■編集実行画面

これで修正画面の一連の動作ができるようになったので、次は詳細画面、削除画面へとりかかっていきます。

編集画面の確認画面を作成する

前回作成した修正画面に対して、確認画面を拡張します。

これまでは、確認画面に「sample_text」の項目1つだけしかありませんでしたが、ここに「テキスト」「チェックボックス」「ラジオボタン「セレクトボックス」「テキストエリア」の項目を追加します。

修正画面と、修正確認画面のメソッドを変更したソース全体を記載します。

    /**
     * 修正
     */
    function edit()
    {
        if (isset($_REQUEST["form_id"])) {
            //確認画面の「戻る」ボタンから遷移してきた場合
            $form_id = esc_attr($_REQUEST["form_id"]);

            $sample_name = esc_attr($_REQUEST["sample_name"]);
            $sample_text = esc_attr($_REQUEST["sample_text"]);
            $sample_check = $_REQUEST["sample_check"];
            $sample_radio = esc_attr($_REQUEST["sample_radio"]);
            $sample_select = esc_attr($_REQUEST["sample_select"]);
            $sample_textarea = esc_attr($_REQUEST["sample_textarea"]);

            //チェックボックスの判定
            foreach ($sample_check as $key => $value) {
                if ($value != "") {
                    $sample_check_checked[$key] = "checked";
                }
            }
            
            //ラジオボタンの判定
            for ($i=0; $i<3; $i++) {
                if ($sample_radio == $i) {
                    $sample_radio_checked[$i] = "checked";
                }
            }
            
            //セレクトボックスの判定
            $sample_select_array = array("a", "b", "c", "d", "e");
            foreach ($sample_select_array as $key => $value) {
                if ($sample_select == $value) {
                    $sample_select_selected[$key] = "selected";
                }
            }

            $create_date = esc_attr($_REQUEST["create_date"]);
        } else {
            
            //一覧画面から「編集」ボタンを押下した場合
            
            //押されたボタンのIDを取得する
            if (array_search("編集", $_REQUEST["submit"]["edit"])) {
                $form_id = array_search("編集", $_REQUEST["submit"]["edit"]);
            }

            global $wpdb;
            $tbl_name = $wpdb->prefix . 'sample_mst';
            $sql = "SELECT * FROM {$tbl_name} WHERE id = %d;";
            $prepared = $wpdb->prepare($sql, $form_id);
            $rows = $wpdb->get_results($prepared, ARRAY_A);

            $sample_name = $rows[0]["sample_name"];
            $sample_text  = $rows[0]["sample_text "];
            $sample_check  = $rows[0]["sample_check "];
            $sample_radio  = $rows[0]["sample_radio "];
            $sample_select  = $rows[0]["sample_select "];
            $sample_textarea = $rows[0]["sample_textarea"];

            $create_date = $rows[0]["create_date"];
        }

        //データ一覧
        echo <<< EOL
<form action="" method="post">
    <h2>データ編集</h2>

    <div class="wrap">

    <table class="wp-list-table widefat striped posts">
        <tr>
            <td>ID</td>
            <td>{$form_id}</td>
        </tr>
        <tr>
            <td>NAME</td>
            <td>
                <input type="text" name="sample_name" value="{$sample_name}">
            </td>
        </tr>

        <tr>
            <td>テキスト</td>
            <td>
                <input type="text" name="sample_text" value="{$sample_text}">
            </td>
        </tr>
        <tr>
            <td>チェックボックス</td>
            <td>
                チェック値1<input type="checkbox" name="sample_check[]" value="1" {$sample_check_checked[0]}>
                チェック値2<input type="checkbox" name="sample_check[]" value="2" {$sample_check_checked[1]}>
                チェック値3<input type="checkbox" name="sample_check[]" value="3" {$sample_check_checked[2]}>
            </td>
        </tr>
        <tr>
            <td>ラジオボタン</td>
            <td>
                ラジオ値1<input type="radio" name="sample_radio" value="1" {$sample_radio_checked[0]}>
                ラジオ値2<input type="radio" name="sample_radio" value="2" {$sample_radio_checked[1]}>
                ラジオ値3<input type="radio" name="sample_radio" value="3" {$sample_radio_checked[2]}>
            </td>
        </tr>
        <tr>
            <td>セレクトボックス</td>
            <td>
                <select name="sample_select">
                    <option value="a" {$sample_select_selected[0]}>選択a</option>
                    <option value="b" {$sample_select_selected[1]}>選択b</option>
                    <option value="c" {$sample_select_selected[2]}>選択c</option>
                    <option value="d" {$sample_select_selected[3]}>選択d</option>
                    <option value="e" {$sample_select_selected[4]}>選択e</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>テキストエリア</td>
            <td>
                <textarea name="sample_textarea" cols="30" rows="5">{$sample_textarea}</textarea>
            </td>
        </tr>

        <tr>
            <td>登録日時</td>
            <td>{$create_date}</td>
        </tr>
    </table>

    <input type='submit' name='submit[edit_check]' class='button-primary' value='編集内容を確認する' />
    <input type='submit' name='submit[]' class='button-primary' value='戻る' />

    <input type="hidden" name="form_id" value="{$form_id}">
    <input type="hidden" name="create_date" value="{$create_date}">

    </div>

</form>
EOL;
    }

    /**
     * 編集確認
     */
    function edit_check()
    {
        $form_id = esc_attr($_REQUEST["form_id"]);
        $sample_name = esc_attr($_REQUEST["sample_name"]);

        $sample_text = esc_attr($_REQUEST["sample_text"]);
        $sample_check = esc_attr($_REQUEST["sample_check"]);
        $sample_radio = esc_attr($_REQUEST["sample_radio"]);
        $sample_select = esc_attr($_REQUEST["sample_select"]);
        $sample_textarea = esc_attr($_REQUEST["sample_textarea"]);

        $create_date = esc_attr($_REQUEST["create_date"]);

        if (!strlen($sample_name)) {
            echo _e('NAMEが未入力です');
        }

        //チェックボックスの値を処理
        if (is_array($_REQUEST["sample_check"])) {
            foreach ($_REQUEST["sample_check"] as $key => $value) {
                $disp_checkbox .= "チェック値" . $value . "<br />";
                $hidden_checkbox .= '<input type="hidden" name="sample_check[]" value="' . $value . '">';
            }
        }

        //テキストエリア整形(表示用)
        $sample_textarea_disp = nl2br($sample_textarea);

        //データ一覧
        echo <<< EOL
<form action="" method="post">
    <h2>データ編集確認</h2>

    <div class="wrap">

        <table class="wp-list-table widefat striped posts">
            <tr> 
                <td>ID</td>
                <td>{$form_id}</td>
            </tr>
            <tr> 
                <td>NAME</td>
                <td>{$sample_name}</td>
            </tr>
            <tr> 
                <td>テキスト</td>
                <td>{$sample_text}</td>
            </tr>
            <tr> 
                <td>チェックボックス</td>
                <td>
                    {$disp_checkbox}
                </td>
            </tr>
            <tr> 
                <td>ラジオボタン</td>
                <td>{$sample_radio}</td>
            </tr>
            <tr> 
                <td>セレクトボックス</td>
                <td>{$sample_select}</td>
            </tr>
            <tr> 
                <td>テキストエリア</td>
                <td>{$sample_textarea}</td>
            </tr>
        </table>

    <input type="hidden" name="form_id" value="{$form_id}">

    <input type="hidden" name="sample_name" value="{$sample_name}">
    <input type="hidden" name="sample_text" value="{$sample_text}">
    {$hidden_checkbox}
    <input type="hidden" name="sample_radio" value="{$sample_radio}">
    <input type="hidden" name="sample_select" value="{$sample_select}">
    <input type="hidden" name="sample_textarea" value="{$sample_textarea_disp}">

    <input type="hidden" name="create_date" value="{$create_date}">

    <input type='submit' name='submit[edit_exec]' class='button-primary' value='編集する' />
    <input type='submit' name='submit[edit]' class='button-primary' value='戻る' />

    </div>

</form>
EOL;
    }

値のチェック方法や、受け渡しの方法など、細かい箇所は修正する必要があると思いますが、全体の入力→確認への流れはこのような形で作りました。

これを実行すると、次のような入力画面と確認画面になります。

まず、一覧画面になります。

次に、一覧画面から「編集」を選択したデータを表示します。

編集内容を入力します。

「編集内容を確認する」ボタンを押下すると、確認画面に入力した値が表示されます。

確認画面から「戻る」ボタンを押しても、入力値を保持したまま、前画面へ遷移することもできます。

編集画面の管理項目を追加する

前回追加したテーブルの値を編集する為に、管理画面の「編集時」の表示を変更します。

これまでは「NAME」という値の編集しかできませんでしたが、
ここに管理項目として「テキスト」「チェックボックス」「ラジオボタン」「セレクトボックス」「テキストエリア」という項目を追加します。

修正時のメソッド全体は以下のようになります。

	/**
	 * 修正
	 */
	function edit()
	{

		if (isset($_REQUEST["form_id"])) {
			$form_id = esc_attr($_REQUEST["form_id"]);
			$sample_name = esc_attr($_REQUEST["sample_name"]);
			$create_date = esc_attr($_REQUEST["create_date"]);
		} else {
			//押されたボタンのIDを取得する
			if (array_search("編集", $_REQUEST["submit"]["edit"])) {
				$form_id = array_search("編集", esc_attr($_REQUEST["submit"]["edit"]));
			}

			global $wpdb;

			$tbl_name = $wpdb->prefix . 'sample_mst';
			$sql = "SELECT * FROM {$tbl_name} WHERE id = %d;";
			$prepared = $wpdb->prepare($sql, $form_id);
			$rows = $wpdb->get_results($prepared, ARRAY_A);

			$sample_name = $rows[0]["sample_name"];

			$sample_text  = $rows[0]["sample_text "];
			$sample_check  = $rows[0]["sample_check "];
			$sample_radio  = $rows[0]["sample_radio "];
			$sample_select  = $rows[0]["sample_select "];
			$sample_textarea = $rows[0]["sample_textarea"];

			$create_date = $rows[0]["create_date"];
		}

		//データ一覧
		echo <<< EOL
<form action="" method="post">
	<h2>データ編集</h2>

	<div class="wrap">

	<table class="wp-list-table widefat striped posts">
		<tr>
			<td>ID</td>
			<td>{$form_id}</td>
		</tr>
		<tr>
			<td>NAME</td>
			<td>
				<input type="text" name="sample_name" value="{$sample_name}">
			</td>
		</tr>

		<tr>
			<td>テキスト</td>
			<td>
				<input type="text" name="sample_text" value="{$sample_text}">
			</td>
		</tr>
		<tr>
			<td>チェックボックス</td>
			<td>
				チェック値1<input type="checkbox" name="sample_check" value="1">
				チェック値2<input type="checkbox" name="sample_check" value="2">
				チェック値3<input type="checkbox" name="sample_check" value="3">
			</td>
		</tr>
		<tr>
			<td>ラジオボタン</td>
			<td>
				ラジオ値1<input type="radio" name="sample_radio" value="1">
				ラジオ値2<input type="radio" name="sample_radio" value="2">
				ラジオ値3<input type="radio" name="sample_radio" value="3">
			</td>
		</tr>
		<tr>
			<td>セレクトボックス</td>
			<td>
				<select name="sample_select">
					<option value="a">選択a</option>
					<option value="b">選択b</option>
					<option value="c">選択c</option>
					<option value="d">選択d</option>
					<option value="e">選択e</option>
				</select>
			</td>
		</tr>
		<tr>
			<td>テキストエリア</td>
			<td>
				<textarea name="sample_textarea" cols="30" rows="5">{$sample_textarea}</textarea>
			</td>
		</tr>

		<tr>
			<td>登録日時</td>
			<td>{$create_date}</td>
		</tr>
	</table>

	<input type='submit' name='submit[edit_check]' class='button-primary' value='編集内容を確認する' />
	<input type='submit' name='submit[]' class='button-primary' value='戻る' />

	<input type="hidden" name="form_id" value="{$form_id}">
	<input type="hidden" name="create_date" value="{$create_date}">

	</div>

</form>
EOL;
	}

上記のように書くと、画面は以下のように表示されます。

この増やした項目に対して、登録や修正を行えるようにしていきます。

管理項目を追加する

これまで作ってきたプラグインは、項目が「sample_name」という1つの項目だけを取り扱ってきました。

今後は、sample_nameという項目以外にも、チェックボックス、ラジオボタン、セレクトボックス、テキストエリア、を取り扱う管理画面を作ってみるので、プラグインインストール時に実行されるテーブル作製のcreate table文を拡張してみます。

これまでは、以下のcreate文です。

CREATE TABLE {$table_name} (
id				INT NOT NULL AUTO_INCREMENT,
sample_name		VARCHAR(128),
create_date		DATETIME,
PRIMARY KEY(id)
) {$charset_collate};

これを、次のように拡張します。

CREATE TABLE {$table_name} (
id              INT NOT NULL AUTO_INCREMENT,
sample_name     VARCHAR(128),
sample_text     VARCHAR(256),
sample_check    VARCHAR(256),
sample_radio    VARCHAR(256),
sample_select   VARCHAR(256),
sample_textarea text,
create_date     DATETIME,
PRIMARY KEY(id)
) {$charset_collate};

実行されるタイミングはプラグインをインストールした時に一度実行されるので、メソッド全体では次のようになります。

/**
 * プラグインインストール時
 */
function create_tables_sample_mst()
{
    global $wpdb;

    $charset_collate = "";

    //接頭辞の追加(socal_count_cache)
    $table_name = $wpdb->prefix . 'sample_mst';

    //charsetを指定する
    if (!empty($wpdb->charset)) {
        $charset_collate = "DEFAULT CHARACTER SET {$wpdb->charset} ";
    }

    //照合順序を指定する(ある場合、通常デフォルトのutf8_general_ci)
    if (!empty($wpdb->collate)) {
        $charset_collate .= "COLLATE {$wpdb->collate}";
    }

    $sql = <<< EOL
CREATE TABLE {$table_name} (
id              INT NOT NULL AUTO_INCREMENT,
sample_name     VARCHAR(128),
sample_text     VARCHAR(256),
sample_check    VARCHAR(256),
sample_radio    VARCHAR(256),
sample_select   VARCHAR(256),
sample_textarea text,
create_date     DATETIME,
PRIMARY KEY(id)
) {$charset_collate};
EOL;

    //dbDeltaを実行する為に必要
    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($sql);

    $sample_name = 'テストデータ';

    $table_name = $wpdb->prefix . 'sample_mst';

    $wpdb->insert(
        $table_name,
        array(
            'sample_name' => $sample_name,
            'create_date' => current_time('mysql')
        ) 
    );
}

次回以降、この追加した項目に対して、「登録」「修正」「削除」「詳細」ができるように、管理画面を拡張していきます。

前回まで作った管理テーブルに対し、データ件数が増えてきた場合を想定して、ページング処理を入れます。

前回までの、テーブル一覧部分のコードは以下のとおりです。

	/**
	 * 初期表示
	 */
	function disp()
	{
		//データ一覧
		echo <<< EOL
<form action="" method="post">

	<h2>データ一覧</h2>
	<input type='submit' name='submit[regist]' class='button-primary' value='新規登録' />

	<div class="wrap">

	<table class="wp-list-table widefat striped posts">
		<tr>
			<th nowrap>ID</th>
			<th nowrap>名前</th>
			<th nowrap>登録日時</th>
			<th nowrap>詳細</th>
			<th nowrap>編集</th>
		</tr>
EOL;

		global $wpdb;

		$tbl_name = $wpdb->prefix . 'sample_mst';
		$sql = "SELECT * FROM {$tbl_name} ORDER BY id;";
		$rows = $wpdb->get_results($sql);

		foreach($rows as $row) {
			echo "<tr>";
			echo "<td>" . $row->id . "</td>";
			echo "<td>" . $row->sample_name . "</td>";
			echo "<td>" . $row->create_date . "</td>";
			echo "<td>";
			echo "<input type='submit' name='submit[detail][" . $row->id . "]'";
			echo " class='button-primary' value='詳細' />";
			echo "</td>";
			echo "<td>";
			echo "<input type='submit' name='submit[edit][" . $row->id . "]'";
			echo " class='button-primary' value='編集' />";
			echo "</td>";
			echo "</tr>";
		}
		echo "</table>";
		echo "</div>";
		echo "</form>";
	}

このコードに対し、ページ処理を入れていきます。

まず、現在のページ番号をGETパラメータで受け渡す為、パラメータ取得用の変数を用意し、取得します。

$pageid = filter_input(INPUT_GET, 'pageid');

次に、1ページあたり、何件表示して次のページに移るのか、上限を決定します。

//1ページあたりの件数
$limit = 10;

次に、対象となるデータの総件数を取得します

//DBオブジェクトを用意
global $wpdb;

//全件数取得
$tbl_name = $wpdb->prefix . 'sample_mst';
$sql = "SELECT count(*) AS CNT FROM {$tbl_name}";
$rows = $wpdb->get_results($sql);
$recordcount = $rows[0]->CNT;

ここで、$recordcountという変数に総件数が格納されます。

次に、ページ遷移した時に、データベースからオフセットした値を取得する為に、SQL用にoffset値を決定します。

//offsetの値を決定
$offset = $pageid * $limit;

最後に、データベースにクエリを発行し、データを取得します。
ここのタイミングではlimit件数(10件ごと)にデータを区切って取得しています。

//offset と limitによる画面表示用のデータ取得
$sql = "SELECT * FROM {$tbl_name} ORDER BY id limit {$offset}, {$limit};";

//通常の取得方法(SQL実行結果を、オブジェクトとして取得)
$rows = $wpdb->get_results($sql);

次にページ処理用のメソッドと、それに応じたパラメータを書いておきます。

$args = array(
	'label' => __('Per Page'),
	'default' => 10,
	'option' => 'disp'
);
$page_html = self::pagination($recordcount);

paginationというメソッド名は、function disp()の外側の任意の箇所に記述します。

function pagination($recordcount)
{
	$count = $recordcount;
	$limit = 10;

	//レコード総数がゼロのときは何も出力しない
	if (0 === $count) {
		return '';
	}

	//現在表示中のページ番号(ゼロスタート)
	$intCurrentPage = self::getCurrentPage();

	//ページの最大数
	$intMaxpage = ceil($count / $limit);

	//現在ページの前後3ページを出力
	$intStartpage = (2 < $intCurrentPage) ? $intCurrentPage - 3 : 0;
	$intEndpage = (($intStartpage + 7) < $intMaxpage) ? $intStartpage + 7 : $intMaxpage;

	//url組み立て
	$urlparams = filter_input_array(INPUT_GET);

	$items = [];

	//ページURLの生成
	//最初
	$urlparams['page'] = filter_input(INPUT_GET, 'page');
	$urlparams['pageid'] = 0;
	$items[] = sprintf('<span><a href="?%s">%s</a></span>'
		, http_build_query($urlparams)
		, '最初'
	);

	//表示中のページが先頭ではない時
	if (0 < $intCurrentPage) {
		$urlparams['pageid'] = $intCurrentPage - 1;
		$items[] = sprintf('<span><a href="?%s">%s</a></span>'
			, http_build_query($urlparams)
			, '前へ'
		);
	}

	for ($i = $intStartpage; $i < $intEndpage; $i++) {
		$urlparams['pageid'] = $i;
		$items[] = sprintf('<span%s><a href="?%s">%s</a></span>'
			, ($intCurrentPage == $i) ? ' class="current"' : ''
			, http_build_query($urlparams)
			, $i + 1
		);
	}

	//表示中のページが最後ではない時
	if ($intCurrentPage < $intMaxpage) {
		$urlparams['pageid'] = $intCurrentPage + 1;
		$items[] = sprintf('<span><a href="?%s">%s</a></span>'
			, http_build_query($urlparams)
			, '次へ'
		);
	}

	//最後
	$urlparams['pageid'] = $intMaxpage - 1;
	$items[] = sprintf('<span><a href="?%s">%s</a></span>'
		, http_build_query($urlparams)
		, '最後'
	);

	return $items;
}

最終的に、$page_htmlという変数に、ページング出力用の情報が入るので、それを画面出力用に整形して、出力します。

//ページ部分の表示
echo "<div class='admin_pagination'>";
echo "<ul>";
foreach ($page_html as $key => $value) {
	echo "<li>" . $value . "</li>";
}
echo "</ul>";

このままでは、文字列のみのページ表示になるので、cssでスタイルを調整します。

/* ページング処理 */
.admin_pagination ul li {
	display: inline-block;
	padding: 0px 1px 0px 1px;
	margin: 0px 3px 0px 3px;
	background-color: #DBDBDB;
}
.admin_pagination ul li .current a{
	color: #FFFFFF;
	background-color: #666666;
}
.admin_pagination ul a {
	display: block;
	padding: 8px 10px 8px 10px;
}

これで、テーブルに関連するページング処理の表示ができました。

出力結果は以下のようになります。

試しに3ページ目にアクセスする。

このように表示されます。

作っている最中に、気づきが遅かった部分がありました。
$wpdbのオブジェクトに対し、get_resultsメソッドを使ったSQL実行で、
offset、limitの処理を書いた場合、一般的なSQLの書き方では、
思うような抽出結果が得られませんでした。

SELECT * FROM テーブル名 OFFSET 10 LIMIT 5;

などと書くのはNGで、

SELECT * FROM テーブル名 LIMIT 10, 5;

のように書かないと、想定した出力結果が得られませんでした。
wpdbのget_resultsの仕様ページを見たのですが、明確な記載はありませんでした。
気づくまでに時間がかかってしまいました。

管理画面全体に対して、独自に用意したcssファイルを読み込ませます。

有効化しているテーマのディレクトリの直下に、独自cssファイルを配置します。

有効化しているディレクトリの場所は以下のようになります。

/ワードプレス設置ディレクトリ/wp-content/themes/有効化しているディレクトリ/

ここに、独自cssとして、「my_admin_style.css」を用意する(ファイル名は任意でOKです。

/ワードプレス設置ディレクトリ/wp-content/themes/有効化しているディレクトリ/my_admin_style.css

このように配置します。

次に、テーマディレクトリ直下のfunctions.phpを編集します。
ファイルの一番した等に次のように記述します。

//管理画面に独自CSSファイルを読み込ませる
function my_admin_style()
{
    wp_enqueue_style( 'my_admin_style', get_template_directory_uri().'/my_admin_style.css' );
}
add_action( 'admin_enqueue_scripts', 'my_admin_style' );

ここでポイントとなるのは、追加したcssファイル名「my_admin_style」と同じ要素でadd_actionを記述することです。

これで、管理画面を再読み込みすると、cssが適用されます。

管理画面のデータ一覧表示部分のテーブルが味気のないものだったので、簡単なstyleを記述して少し見やすくしました。

style適用前は以下のような画面でしたが、以下のような表示になっています。

この表示にstyleを適用して見やすくします。

まずは、tableタグを次のようなdivタグで囲います。

<div class="wrap">

次に、tableタグに次のようなクラスを記述します。

class="wp-list-table widefat striped posts"

最後にwrapで囲んだdivを閉じます。

tableを使っている箇所でstyleを整えたいところに適宜、記述していくとよいかと思います。

最初に画面を調整した結果、表示する関数全体としては以下のようになりました。

function disp()
{
    //データ一覧
    echo <<< EOL
<form action="" method="post">

<h2>データ一覧</h2>
<input type='submit' name='submit[regist]' class='button-primary' value='新規登録' />

<div class="wrap">

<table class="wp-list-table widefat striped posts">
    <tr>
        <th nowrap>ID</th>
        <th nowrap>名前</th>
        <th nowrap>登録日時</th>
        <th nowrap>詳細</th>
        <th nowrap>編集</th>
    </tr>
EOL;

    global $wpdb;

    $tbl_name = $wpdb->prefix . 'sample_mst';
    $sql = "SELECT * FROM {$tbl_name} ORDER BY id;";
    $rows = $wpdb->get_results($sql);

    foreach($rows as $row) {
        echo "<tr>";
        echo "<td>" . $row->id . "</td>";
        echo "<td>" . $row->sample_name . "</td>";
        echo "<td>" . $row->create_date . "</td>";
        echo "<td>";
        echo "<input type='submit' name='submit[detail][" . $row->id . "]'";
        echo " class='button-primary' value='詳細' />";
        echo "</td>";
        echo "<td>";
        echo "<input type='submit' name='submit[edit][" . $row->id . "]'";
        echo " class='button-primary' value='編集' />";
        echo "</td>";
        echo "</tr>";
    }
    echo "</table>";
    echo "</div>";
    echo "</form>";
}

表示される結果は次のようになります。

少しだけ、おしゃれになりました。

これまでに作ったプラグインは主に管理画面での操作用に作ってきました。

大まかな動きとしては、DBの登録/修正/削除が管理画面からできていましたが、今度はそれをユーザ画面側に表示することを行います。

ユーザ画面側では、「投稿」「固定ページ」へ自由に表示する為に「ショートコード」という書き方をすることで、DBの値を表示することができます。

これまでに作ったプラグインの中身を表示する為に、以下のような書き方をします。
(便宜上、プラグインプログラムの一番下に書き足します)

/**
 * ショートコード
 */
function samplelistFunction()
{
	//データ一覧
	$disp_html =<<< EOL
<form action="" method="post">
<h2>データ一覧(ショートコードテスト)</h2>
<table>
	<tr>
		<th nowrap>ID</th>
		<th nowrap>名前</th>
		<th nowrap>登録日時</th>
	</tr>
EOL;

	global $wpdb;

	$tbl_name = $wpdb->prefix . 'sample_mst';
	$sql = "SELECT * FROM {$tbl_name} ORDER BY id;";
	$rows = $wpdb->get_results($sql);

	foreach($rows as $row) {

$disp_html .=<<<EOL
	<tr>
		<td>{$row->id}</td>
		<td>{$row->sample_name}</td>
		<td>{$row->create_date}</td>
		<td>
	</tr>
EOL;
	}

	$disp_html .=<<< EOL
	</table>
	</form>
EOL;

	return $disp_html;
}
//「[samplelist]という記述を投稿画面や固定ページに記述する」
add_shortcode('samplelist', 'samplelistFunction');

上記の書き方をすることにより、ユーザ側で、ショートコードタグ「[samplelist]」を記述すると、その部分にDBアクセスした一覧表示テーブルを表示することができます。

色々と応用することができますが、まずは表示できるところまでで、一区切りとします。

データの更新系を考えてみます。

データを更新する場合、当然のように入力値をチェックしないと、整合性が取れないデータがユーザからの入力されてしまいます。

今回はデータの新規登録時に値をチェックする仕組みを入れてみます。

まずは、データをチェックするタイミングを考えます。
新規登録からデータを登録する「登録内容を確認する」(下記、画像ファイルを参照)というボタンを押した時の動作をきっかけにチェックを入れます。

次にソース上で、そのボタンが押された箇所の処理をみます。

    /**
     * 登録確認
     */
    function regist_check()
    {
        $sample_name = $_REQUEST["sample_name"];

        //データ一覧
        echo <<< EOL
<form action="" method="post">
    <h2>データ登録確認</h2>
<table border="1">
    <tr>
        <td>NAME</td>
        <td>{$sample_name}</td>
    </tr>
</table>

<input type="hidden" name="sample_name" value="{$sample_name}">

<input type='submit' name='submit[regist_exec]' class='button-primary' value='登録する' />
<input type='submit' name='submit[regist]' class='button-primary' value='戻る' />
EOL;
        echo "</form>";
    }

単純に入力画面で入力した文字列をそのまま変数に代入して、確認画面を出していることがわかります。

このままでは空白や、危険な文字列が入力された場合に、意図しない動作になってしまいます。

次のように修正します。

    /**
     * 登録確認
     */
    function regist_check()
    {
        //入力値が空白の場合の処理(ここでは単純に0バイトだったら)
        if (!strlen($_REQUEST["sample_name"])) {
            self::regist(false);
            return;
        }
        
        $sample_name = esc_attr($_REQUEST["sample_name"]);

        //データ一覧
        echo <<< EOL
<form action="" method="post">
    <h2>データ登録確認</h2>
<table border="1">
    <tr>
        <td>NAME</td>
        <td>{$sample_name}</td>
    </tr>
</table>

<input type="hidden" name="sample_name" value="{$sample_name}">

<input type='submit' name='submit[regist_exec]' class='button-primary' value='登録する' />
<input type='submit' name='submit[regist]' class='button-primary' value='戻る' />
EOL;
        echo "</form>";
    }

チェック方法が少し荒っぽいですが、未入力チェックと、< > & ” ‘ (小なり、大なり、アンパサンド、ダブルクォート、シングルクォート) 文字参照をエンコードする関数「esc_attr」を処理に入れています。

また、もし入力された値が空白だった場合「self::regist(false)」という形で、また登録画面を呼び出しています。

引数にfalseを渡し、チェック時に何が起きたのかを新規登録画面へ伝えます。

新規登録画面側の処理は、以下のように修正します。

    /**
     * 登録
     */
    function regist($error_message_flg = null)
    {
        if ($error_message_flg !== false) {
            $sample_name = esc_attr($_REQUEST["sample_name"]);
        }

        echo <<< EOL
<form action="" method="post">
    <h2>データ登録</h2>
EOL;

        //エラーメッセージのフラグがfalseの場合、メッセージを表示する
        if ($error_message_flg == false) {
            echo "<div class='updated fade'><p><strong>";
            echo _e('NAMEを入力してください');
            echo "</strong></p></div>";
        }

        echo <<< EOL
    <table border="1">
        <tr>
            <td>NAME</td>
            <td>
                <input type="text" name="sample_name" value="{$sample_name}">
            </td>
        </tr>
    </table>

    <input type='submit' name='submit[regist_check]' class='button-primary' value='登録内容を確認する' />
    <input type='submit' name='submit[]' class='button-primary' value='戻る' />
</form>
EOL;
    }

このように処理を書くことで、未入力の場合には「NAMEを入力してください」
というメッセージが表示されるようになります。

今回は未入力チェックのみの実装でしたが、その他にも入力項目の種類に合わせたチェック方法を実装する場面が出てきます。
当然のごとくエラーの表示場所や、文言、レイアウトなどはもっと工夫する必要があります。

書き方は数多くあるので、もっと良い書き方を考えて改良する予定です。

前回までのプログラムに、新規登録画面を追加します。

まずは、「登録画面」「登録確認画面」「登録完了画面」の処理の為に分岐を作っておきます。
そしてそれぞれ違うメソッドを呼ぶように関数を追加。

	/**
	 * 管理画面のHTMLの生成と表示
	 */
	function sample_plugin()
	{
		if (isset($_REQUEST["submit"]["detail"])) {
			//詳細
			self::detail();
		} else if (isset($_REQUEST["submit"]["edit"])) {
			//修正
			self::edit();
		} else if (isset($_REQUEST["submit"]["edit_check"])) {
			//修正確認
			self::edit_check();
		} else if (isset($_REQUEST["submit"]["edit_exec"])) {
			//修正実行
			self::edit_exec();
		} else if (isset($_REQUEST["submit"]["delete_check"])) {
			//削除確認
			self::delete_check();
		} else if (isset($_REQUEST["submit"]["delete_exec"])) {
			//削除実行
			self::delete_exec();
		} else if (isset($_REQUEST["submit"]["regist"])) {
			//新規登録
			self::regist();
		} else if (isset($_REQUEST["submit"]["regist_check"])) {
			//新規登録確認
			self::regist_check();
		} else if (isset($_REQUEST["submit"]["regist_exec"])) {
			//新規登録
			self::regist_exec();
		} else {
			//初期表示
			self::disp();
		}
	}

次に、プログラム内の任意の箇所に、以下の関数を追加します。

	/**
	 * 登録
	 */
	function regist()
	{
		if (isset($_REQUEST["sample_name"])) {
			$sample_name = $_REQUEST["sample_name"];
		}

		echo <<< EOL
<form action="" method="post">
	<h2>データ登録</h2>
	<table border="1">
		<tr>
			<td>NAME</td>
			<td>
				<input type="text" name="sample_name" value="{$sample_name}">
			</td>
		</tr>
	</table>

	<input type='submit' name='submit[regist_check]' class='button-primary' value='登録内容を確認する' />
	<input type='submit' name='submit[]' class='button-primary' value='戻る' />
</form>
EOL;
	}

	/**
	 * 登録確認
	 */
	function regist_check()
	{
		$sample_name = $_REQUEST["sample_name"];

		//データ一覧
		echo <<< EOL
<form action="" method="post">
	<h2>データ登録確認</h2>
EOL;

		echo <<<EOL
<table border="1">
	<tr>
		<td>NAME</td>
		<td>{$sample_name}</td>
	</tr>
</table>

<input type="hidden" name="sample_name" value="{$sample_name}">

<input type='submit' name='submit[regist_exec]' class='button-primary' value='登録する' />
<input type='submit' name='submit[regist]' class='button-primary' value='戻る' />
EOL;
		echo "</form>";
	}


	/**
	 * 登録実行
	 */
	function regist_exec()
	{
		global $wpdb;

		$sample_name = $_REQUEST["sample_name"];

		//投稿を登録
		$table_name = $wpdb->prefix . 'sample_mst';
		$result = $wpdb->insert(
			$table_name,
			array(
				'sample_name' => $sample_name,
				'create_date' => current_time('mysql')
			)
		);

		//データ一覧
		echo <<< EOL
<form action="" method="post">
	<h2>データ登録</h2>
	<div class='updated fade'><p><strong>
EOL;
		echo _e('登録が完了しました');
		echo <<<EOL
</strong></p></div>
<input type='submit' name='submit[]' class='button-primary' value='戻る' />
EOL;
		echo "</form>";
	}

これで、新規登録ボタンを押した後に、登録フォーム→確認画面→完了画面へ遷移し、最後にDB内にデータを保存する流れができます。

■新規登録ボタン追加

■登録フォームの表示

■確認画面の表示

■完了画面の表示

ちなみに入力値チェックは確認画面のタイミングで書く必要がありますので、次の課題として進めます。

かなり簡単な登録画面(項目も1個のみ)ですが、文字列の登録が管理画面上から可能になりました。

作成中のプログラムに、削除機能をつけてみます。

まずは、function sample_plugin()に対して、削除確認画面と、
削除実行画面のメソッドをつけます。

	/**
	 * 管理画面のHTMLの生成と表示
	 */
	function sample_plugin()
	{
		if (isset($_REQUEST["submit"]["detail"])) {
			//詳細
			self::detail();
		} else if (isset($_REQUEST["submit"]["edit"])) {
			//修正
			self::edit();
		} else if (isset($_REQUEST["submit"]["edit_check"])) {
			//修正確認
			self::edit_check();
		} else if (isset($_REQUEST["submit"]["edit_exec"])) {
			//修正実行
			self::edit_exec();
		} else if (isset($_REQUEST["submit"]["delete_check"])) {
			//削除確認
			self::delete_check();
		} else if (isset($_REQUEST["submit"]["delete_exec"])) {
			//削除実行
			self::delete_exec();
		} else {
			//初期表示
			self::disp();
		}
	}

次に関数delete_checkとdelete_execをそれぞれ新規作成します。

削除確認画面は以下のように書きます。
これは修正確認画面の応用なので、書き方によっては同一にできるかと思います。

	/**
	 * 削除確認
	 */
	function delete_check()
	{
		$form_id = $_REQUEST["form_id"];

		global $wpdb;

		$tbl_name = $wpdb->prefix . 'sample_mst';
		$sql = "SELECT * FROM {$tbl_name} WHERE id = %d;";
		$prepared = $wpdb->prepare($sql, $form_id);
		$rows = $wpdb->get_results($prepared, ARRAY_A);

		//データ一覧
		echo <<< EOL
<form action="" method="post">
	<h2>データ削除確認</h2>
	<table border="1">
		<tr>
			<td>ID</td>
			<td>{$form_id}</td>
		</tr>
		<tr>
			<td>NAME</td>
			<td>{$rows[0]["sample_name"]}</td>
		</tr>
		<tr>
			<td>登録日時</td>
			<td>{$rows[0]["create_date"]}</td>
		</tr>
	</table>

	<input type="hidden" name="form_id" value="{$form_id}">

	<input type='submit' name='submit[delete_exec]' class='button-primary' value='削除する' />
	<input type='submit' name='submit[edit]' class='button-primary' value='戻る' />
EOL;
		echo "</form>";
	}

次に削除実行の関数を追加します。

	/**
	 * 削除実行
	 */
	function delete_exec()
	{
		$form_id = $_REQUEST["form_id"];

		//データを削除
		global $wpdb;
		$tbl_name = $wpdb->prefix . 'sample_mst';
		$sql = "DELETE FROM {$tbl_name} WHERE id = %s;";
		$dlt = $wpdb->query($wpdb->prepare($sql, $form_id));

		//データ一覧
		echo <<< EOL
<form action="" method="post">
	<h2>データ編集認</h2>
EOL;

		echo "<div class='updated fade'><p><strong>";
		echo _e('削除が完了しました');
		echo "</strong></p></div>";

		echo <<<EOL
<input type='submit' name='submit[]' class='button-primary' value='戻る' />
EOL;
		echo "</form>";
	}

上記の機能を書くことで、データ一覧画面から詳細画面→削除確認画面→削除実行の流れができています。
書き方は千差万別でもっと効率のよい書き方もあると思います。
そこは今度プラグインの調整を続けていく際に強化していきます。

前回作った詳細一覧に対し、「編集」ボタンをつけて、
1レコードづつデータ編集できるようにする。

各ボタンごとにメソッドを分けて処理を書いたので、ソースは少し長めになります。
ボタンごとにname属性に違う記述(やりたい役割ごとに名称を変える)し、
そのname属性をもとにfunction sample_plugin()の中で呼び出すメソッドを分けています。

なにも押下されなかった場合は、初期表示となり、その後、詳細表示(一覧)、
編集、編集確認、編集完了、というそれぞれのメソッドを用意しています。

もっと良い書き方があると思いますが、ひとまず更新はできているのでブログ記事化します。

	/**
	 * 管理画面のHTMLの生成と表示
	 */
	function sample_plugin()
	{
		if (isset($_REQUEST["submit"]["detail"])) {
			//詳細
			self::detail();
		} else if (isset($_REQUEST["submit"]["edit"])) {
			//修正
			self::edit();
		} else if (isset($_REQUEST["submit"]["edit_check"])) {
			//修正確認
			self::edit_check();
		} else if (isset($_REQUEST["submit"]["edit_exec"])) {
			//修正実行
			self::edit_exec();
		} else {
			//初期表示
			self::disp();
		}
	}

	/**
	 * 初期表示
	 */
	function disp()
	{
		//データ一覧
		echo <<< EOL
<form action="" method="post">
	<h2>データ一覧</h2>
	<table>
		<tr>
			<th nowrap>ID</th>
			<th nowrap>名前</th>
			<th nowrap>登録日時</th>
			<th nowrap>詳細</th>
			<th nowrap>編集</th>
		</tr>
EOL;

		global $wpdb;

		$tbl_name = $wpdb->prefix . 'sample_mst';
		$sql = "SELECT * FROM {$tbl_name} ORDER BY id;";
		$rows = $wpdb->get_results($sql);

		foreach($rows as $row) {
			echo "<tr>";
			echo "<td>" . $row->id . "</td>";
			echo "<td>" . $row->sample_name . "</td>";
			echo "<td>" . $row->create_date . "</td>";
			echo "<td>";
			echo "<input type='submit' name='submit[detail][" . $row->id . "]'";
			echo " class='button-primary' value='詳細' />";
			echo "</td>";
			echo "<td>";
			echo "<input type='submit' name='submit[edit][" . $row->id . "]'";
			echo " class='button-primary' value='編集' />";
			echo "</td>";
			echo "</tr>";
		}
		echo "</table>";
		echo "</form>";
	}

	/**
	 * 詳細表示
	 */
	function detail()
	{
		//押されたボタンのIDを取得する
		if (array_search("詳細", $_REQUEST["submit"]["detail"])) {
			$form_id = array_search("詳細", $_REQUEST["submit"]["detail"]);
		}

		//データ一覧
		echo <<< EOL
<form action="" method="post">
	<h2>データ詳細</h2>
EOL;

		global $wpdb;

		$tbl_name = $wpdb->prefix . 'sample_mst';
		$sql = "SELECT * FROM {$tbl_name} WHERE id = %d;";
		$prepared = $wpdb->prepare($sql, $form_id);
		$rows = $wpdb->get_results($prepared, ARRAY_A);

		echo <<<EOL
<table border="1">
	<tr>
		<td>ID</td>
		<td>{$rows[0]["id"]}</td>
	</tr>
	<tr>
		<td>NAME</td>
		<td>{$rows[0]["sample_name"]}</td>
	</tr>
	<tr>
		<td>登録日時</td>
		<td>{$rows[0]["create_date"]}</td>
	</tr>
</table>
<input type='submit' name='submit[]' class='button-primary' value='戻る' />
EOL;
		echo "</form>";
	}

	/**
	 * 修正
	 */
	function edit()
	{
		if (isset($_REQUEST["form_id"])) {
			$form_id = $_REQUEST["form_id"];
			$sample_name = $_REQUEST["sample_name"];
			$create_date = $_REQUEST["create_date"];
		} else {
			//押されたボタンのIDを取得する
			if (array_search("編集", $_REQUEST["submit"]["edit"])) {
				$form_id = array_search("編集", $_REQUEST["submit"]["edit"]);
			}

			global $wpdb;

			$tbl_name = $wpdb->prefix . 'sample_mst';
			$sql = "SELECT * FROM {$tbl_name} WHERE id = %d;";
			$prepared = $wpdb->prepare($sql, $form_id);
			$rows = $wpdb->get_results($prepared, ARRAY_A);

			$sample_name = $rows[0]["sample_name"];
			$create_date = $rows[0]["create_date"];
		}

		//データ一覧
		echo <<< EOL
<form action="" method="post">
	<h2>データ編集</h2>
EOL;


		echo <<<EOL
<table border="1">
	<tr>
		<td>ID</td>
		<td>{$form_id}</td>
	</tr>
	<tr>
		<td>NAME</td>
		<td>
			<input type="text" name="sample_name" value="{$sample_name}">
		</td>
	</tr>
	<tr>
		<td>登録日時</td>
		<td>{$create_date}</td>
	</tr>
</table>

<input type="hidden" name="form_id" value="{$form_id}">
<input type="hidden" name="create_date" value="{$create_date}">

<input type='submit' name='submit[edit_check]' class='button-primary' value='編集内容を確認する' />
<input type='submit' name='submit[]' class='button-primary' value='戻る' />
EOL;
		echo "</form>";
	}

	/**
	 * 編集確認
	 */
	function edit_check()
	{
		$form_id = $_REQUEST["form_id"];
		$sample_name = $_REQUEST["sample_name"];
		$create_date = $_REQUEST["create_date"];

		//データ一覧
		echo <<< EOL
<form action="" method="post">
	<h2>データ編集確認</h2>
EOL;

		echo <<<EOL
<table border="1">
	<tr>
		<td>ID</td>
		<td>{$form_id}</td>
	</tr>
	<tr>
		<td>NAME</td>
		<td>{$sample_name}</td>
	</tr>
</table>

<input type="hidden" name="form_id" value="{$form_id}">
<input type="hidden" name="sample_name" value="{$sample_name}">
<input type="hidden" name="create_date" value="{$create_date}">

<input type='submit' name='submit[edit_exec]' class='button-primary' value='編集する' />
<input type='submit' name='submit[edit]' class='button-primary' value='戻る' />
EOL;
		echo "</form>";
	}

	/**
	 * 編集実行
	 */
	function edit_exec()
	{
		global $wpdb;

		$form_id = $_REQUEST["form_id"];
		$sample_name = $_REQUEST["sample_name"];
		$update_date = date("Y-m-d H:i:s");

		//投稿を更新
		$tbl_name = $wpdb->prefix . 'sample_mst';
		$result = $wpdb->update(
			$tbl_name,
			array('sample_name' => $sample_name,),
			array('id' => $form_id,),
			array('%s'),
			array('%d')
		);

		//データ一覧
		echo <<< EOL
<form action="" method="post">
	<h2>データ編集認</h2>
EOL;

		echo "<div class='updated fade'><p><strong>";
		echo _e('更新が完了しました');
		echo "</strong></p></div>";

		echo <<<EOL
<input type='submit' name='submit[]' class='button-primary' value='戻る' />
EOL;
		echo "</form>";
	}

上記のコードを実行した時の画面を張っておきます。
一覧表示から、編集、確認、完了という、一般的な編集処理ができます。

見た目のレイアウト調整については別な機会にまとめて、整理しようと思っています。
まずは確実に動くものを仕上げていきます。

■一覧画面

■編集を押した時

■編集確認画面

■編集完了画面

管理画面に詳細画面を追加する

先日追加した「function sample_plugin()」には、テーブルの値をだた一覧表示しただけでしたので、今回はその一覧から詳細画面を表示する。という部分を作ってみます。

まず、sample_plugin()という関数は以下のように書いていました。

	/**
	 * 管理画面のHTMLの生成と表示
	 */
	function sample_plugin()
	{
		echo <<< EOL
<h1>sample_plugin メインページ</h1>
ここにHTMLテンプレートを生成していきます。
EOL;

		//データ一覧
		echo <<< EOL
		<h2>データ一覧</h2>
		<table>
			<tr>
				<th nowrap>ID</th>
				<th nowrap>名前</th>
				<th nowrap>登録日時</th>
				<th nowrap>詳細</th>
			</tr>
EOL;

		global $wpdb;
		$tbl_name = $wpdb->prefix . 'sample_mst';
		$sql = "SELECT * FROM {$tbl_name} ORDER BY id;";
		$rows = $wpdb->get_results($sql);

		foreach($rows as $row) {
			echo "<tr>";
			echo "<td nowrap>" . $row->id . "</td>";
			echo "<td nowrap>" . $row->sample_name . "</td>";
			echo "<td nowrap>" . $row->create_date . "</td>";
			echo "<td nowrap>";
			echo "<input type='submit' name='submit[detail][" . $row->id . "]'";
			echo " class='button-primary' value='詳細' />";
			echo "</tr>";
		}
		echo "</table>";
	}

上記の部分を、別な関数に移し、ボタンによって表示する情報を切り替えるように改造します。

ボタンごとに画面を切り替える為、function sample_plugin()を以下のように変更しました。

/**
 * 管理画面のHTMLの生成と表示
 */
function sample_plugin()
{
	if (isset($_REQUEST["submit"]["detail"])) {
		self::detail(); //詳細
	} else if (isset($_REQUEST["submit"]["edit"])) {
		self::edit(); //修正
	} else {
		self::disp(); //初期表示
	}
}

「$_REQUEST[“submit”][“detail”]」という部分が、HTML上にあるボタンのname属性によって切り替えるポイントとなります。(詳細か編集か初期表示かを分けています)
もっと良い方法があるかもしれませんが、間違いなく動作するので、一旦これで進めます。

次に「詳細画面」を表示する為の関数function detail()を新規に書きます。

	/**
	 * 詳細表示
	 */
	function detail()
	{
		//押されたボタンのIDを取得する
		if (array_search("詳細", $_REQUEST["submit"]["detail"])) {
			$form_id = array_search("詳細", $_REQUEST["submit"]["detail"]);
		}

		//データ一覧
		echo <<< EOL
<form action="" method="post">
	<h2>データ詳細</h2>
EOL;

		global $wpdb;

		$tbl_name = $wpdb->prefix . 'sample_mst';
		$sql = "SELECT * FROM {$tbl_name} WHERE id = %d;";
		$prepared = $wpdb->prepare($sql, $form_id);
		$rows = $wpdb->get_results($prepared, ARRAY_A);

		echo <<<EOL
<table border="1">
	<tr>
		<td>ID</td>
		<td>{$rows[0]["id"]}</td>
	</tr>
	<tr>
		<td>NAME</td>
		<td>{$rows[0]["sample_name"]}</td>
	</tr>
	<tr>
		<td>登録日時</td>
		<td>{$rows[0]["create_date"]}</td>
	</tr>
</table>
<input type='submit' name='submit[]' class='button-primary' value='戻る' />
EOL;
		echo "</form>";
	}

上記の関数を用意することで、一覧表示の「詳細」ボタンを押した後に、詳細画面へ遷移し、各データの詳細を表示することが可能になります。

応用次第では、管理画面の色々な場面で編集用の画面が作れるようになります。

管理画面にアクセスした際、初期表示を行います。

あらかじめテーブル「wp_sample_mst」にテスト用データを3件程登録しておきます。
前回の投稿で作成した関数「function sample_plugin()」に、下記のようにデータベースにアクセスしてデータを取得するSQLを書きます。

	/**
	 * 管理画面のHTMLの生成と表示
	 */
	function sample_plugin()
	{
		echo <<< EOL
<h1>sample_plugin メインページ</h1>
ここにHTMLテンプレートを生成していきます。
EOL;
		//データ一覧
		echo <<< EOL
<h2>データ一覧</h2>
<table>
<tr>
<th nowrap>ID</th>
<th nowrap>名前</th>
<th nowrap>登録日時</th>
			</tr>
EOL;
		global $wpdb;
		$tbl_name = $wpdb->prefix . 'sample_mst';
		$sql = "SELECT * FROM {$tbl_name} ORDER BY id;";
		$rows = $wpdb->get_results($sql);
		foreach($rows as $row) {
			echo "<tr>";
			echo "<td nowrap>" . $row->id . "</td>";
			echo "<td nowrap>" . $row->sample_name . "</td>";
			echo "<td nowrap>" . $row->create_date . "</td>";
			echo "</tr>";
		}
		echo "</table>";
	}

上記の例では、テストデータを3件取得して表示しています。

実行結果は以下のようになります。

テーブルに登録したテストデータ3件の表示がされました。
今後、このデータを修正、削除、登録ができるように進めます。

前回までの投稿で、wordpress管理画面のメニューに「SamplePlugin1」というメニューが追加されました。

(下記画像を参照)

001

今回はこのメニューをクリックした時、右側のページにHTMLを生成して表示する動作を作ってみます。

コードは以下のように記述します。
関数「add_pages」の部分の「add_menu_page」の引数に
「array($this, ‘sample_plugin’)」と書いている部分があります。

	function add_pages()
	{
		add_menu_page(
			'SamplePlugin1 Plugin Settings',
			'SamplePlugin1',
			'manage_options',
			'SamplePluginMenu',
			array($this, 'sample_plugin')
		);
	}

この「sample_plugin」という名前の関数(メソッド)を新規作成します。
例えば、以下のように書きます。

	/**
	 * 管理画面のHTMLの生成と表示
	 */
	function sample_plugin()
	{
		
		echo <<< EOL



<h1>sample_plugin メインページ</h1>


ここにHTMLテンプレートを生成していきます。

EOL;
		
	}

上記のように記述して、管理メニューの「SamplePlugin1」を押すと、画面は以下のように表示されます。

002

このようにして、管理項目などを表示するHTMLを生成していきます。

プラグインのアンインストール時の動きを書きます。

まず、前回のプラグイン停止時の動きと同じように、クラスの外で
次のように書きます。

//アンインストール時の設定
register_uninstall_hook(__FILE__, array('SamplePlugin1', 'myplugin_uninstall'));

続いて、クラスの中で次のように書きます。

	/**
	 * 停止時の実行
	 */
	function myplugin_unactivate()
	{
		global $wpdb;

		//削除するテーブル名の決定
		$table_name = $wpdb->prefix . 'sample_mst';

		//テーブル削除
		$sql_drop = "DROP TABLE " . $table_name . ";";
		$wpdb->query($sql_drop);
	}

こうすることで、プラグインのアンインストール時に、メソッド「myplugin_unactivate」が呼び出されることになります。

1 / 512345