WordPressプラグインの作り方~WP開発者リソースを読む~

イントロダクション

WordPressを使用して、プラグインを作成しています。しかし、プラグインで更新処理などを行おうとした時には、ファイルのパーミッション(権限)などの問題でファイルへHTTP(S)ではアクセスできません。
具体的には下のような形ではアクセスできないということです。

https://zenryokuservice.com/wp/wp-content/plugin/プラグイン名/index.php

これを解決しないことには、プラグイン作製ができません。。。どうしたものか?と悩んでいたら「WordPress開発者リソース」を見つけたのでそれを読み進めようということになりました。

本記事の内容

  1. プラグインフォルダの作成

  2. プラグインファイルの作成

  3. フックについて
    1-1.基本的なフック
    1-2.フックの追加方法
    1-3.プラグインフォルダ作成のまとめ

  4. PHPファイルを作成する
    2-1.プラグインPHPを作成する
    2-2.add_menu_page()関数について

  5. プラグインの定義
    3-1.コメントで作る
    3-1.自作要件について

  6. 作成した画面のコード
    4-1.ディレクトリのパス取得関数
    4-2.WordPressの定数
    4-3.HttpGET関数の使い方
    4-4.#Http POSTの使い方
    4-5.#Ajaxの使い方※調査中

  7. 課題

WordPress 開発者リソースを読む

大まかに手順書とかのドキュメントリソース(資源)ということです。下のような記述もあり、大変わかりやすい内容だと思います。

最も単純に言えば、WordPress プラグインは、WordPress プラグイン ヘッダー コメントを含む PHP ファイルです。すべてのプラグインのファイルが 1 か所にきちんと整理されるように、プラグインを保持するディレクトリを作成することを強くお勧めします。

つまりは、プラグインは作成するときに一つのフォルダ内に作成すると、まとまっているので管理しやすいので、推奨します。ということでした。

プラグインフォルダの作成

参照先
今回は「CustomQuestionary」というプラグインを作成しますので、次のようなフォルダを作成しました。
wordPressフォルダから「/wp-content/plugins」フォルダのキャプチャです。

そして、WPプラグインは下記(引用)のように、アクションとフィルターがあります。

WordPress 内には、アクションとフィルターという 2 種類のフックがあります。アクションを使用すると、WordPress の機能を追加または変更できます。一方、フィルターを使用すると、コンテンツが読み込まれて Web サイト ユーザーに表示されるときにコンテンツを変更できます。

プラグインファイルの作成

プラグインのプラグインたる部分です。早い話が、プラグインを有効にした時に表示される画面の部分ということです。
主に起動するプラグインに設定する情報の入力、操作するための情報の入力を行います。

プラグインの表示を行う

フォルダ=ディレクトリを作成したら、フォルダと同じ名前のPHPファイルを作成します。
PHPファイルの内容は以下のようになっています。

<?php
/*
  Plugin Name: SamplePlugin
  Plugin URI:https://zenryokuservice.com/wp/2024/01/06/wordpress%e3%83%97%e3%83%a9%e3%82%b0%e3%82%a4%e3%83%b3%e3%81%ae%e4%bd%9c%e3%82%8a%e6%96%b9/
  Description: サンプルプラグインです。これはプラグインの作成方法を学習するのに使用します。
  Version: 1.0.0
  Author: Takunoji
  Author URI: https://twitter.com/java_takunoji
  License: GPLv2
 */

?>

これを表示すると下のようになります。プラグインは有効化していません。

トップレベルメニューの追加

add_menu_page()を使用して追加します。
具体的には下のように表示されるものの事をいうようです。

メニュー追加の関数「add_menu_page()」のシグニチャ、これは、「admin_menu」のフックで動かす必要があるようです。

add_menu_page(
    string $page_title,      // メニューが選択されたときにページのタイトルタグに表示されるテキスト。
    string $menu_title,      // メニューに使用されるテキスト。
    string $capability,      // このメニューをユーザーに表示するために必要な機能。
    string $menu_slug,       // このメニューを参照するスラッグ名。このメニュー ページに対して一意である
    callable $function = '', // このページのコンテンツを出力するために呼び出される関数
    string $icon_url = '',   // このメニューに使用されるアイコンの URL。
    int $position = null     // この項目が表示されるメニュー順序内の位置。
);

最後の引数にある表示する位置については、最後の引数の値で位置取りを決定するようです。

2 – ダッシュボード
4 – セパレーター
5 – 投稿
10 – メディア
15 – リンク
20 – ページ
25 – コメント
59 – セパレーター
60 – 外観
65 – プラグイン
70 – ユーザー
75 – ツール
80 – 設定
99 – セパレーター
各ディレクトリのパスを取得する関数

具体的に書いて動かしたコードは下の通りです。

  • samplePlugin.php
<?php
/*
  Plugin Name: SamplePlugin
  Plugin URI:https://zenryokuservice.com/wp/2024/01/06/wordpress%e3%83%97%e3%83%a9%e3%82%b0%e3%82%a4%e3%83%b3%e3%81%ae%e4%bd%9c%e3%82%8a%e6%96%b9/
  Description: サンプルプラグインです。これはプラグインの作成方法を学習するのに使用します。
  Version: 1.0.0
  Author: Takunoji
  Author URI: https://twitter.com/java_takunoji
  License: GPLv2
 */

 add_action(
   'admin_menu',
   function(){
         add_menu_page(
             '管理メニュータイトル' ,
             'トップメニューサンプル' ,
             'manage_options' ,
             'top_menu_sample' ,
             'render_topmenu_contents' ,
             null ,
             90
         );

         add_submenu_page(
             'top_menu_sample' ,
             'サブメニュータイトル' ,
             'サブメニューサンプル' , 
             'manage_options' , 
             'sub_menu_sample' , 
             'render_submenu_contents'
         );
     }
 );

 function render_topmenu_contents() {
     ?>
         <div class="wrap">
             <h1>トップメニュー設定</h1>
             <p>Hello admin TOP menu !!</p>
         </div>
     <?php
 }

 function render_submenu_contents() {
     ?>
         <div class="wrap">
             <h1>サブメニュー設定</h1>
             <p>Hello admin SUB menu !!</p>
         </div>
     <?php
 }

?>

1.add_action()関数で、'admin_menu'に「add_menu_page()」と「add_submenu_page()」を使用してメニューページの追加を行います。「render_topmenu_contents」という関数でメニューページを作成・表示します。

 add_action( 'admin_menu',
   function(){
         add_menu_page(
             '管理メニュータイトル' ,
             'トップメニューサンプル' ,
             'manage_options' ,
             'top_menu_sample' ,
             'render_topmenu_contents' ,
             null ,
             90
         );
  1. メニューページを作成する
    これは参考ページとしてこのページを参照します。「カスタム設定ページ」を作成します」。ここに「WPOrg」という名前のページを作成する例が書いてあります。以下はサンプルコードのコピペです。

「wporg_settings_init」関数をadd_action( 'admin_init', 'wporg_settings_init' );で登録します。
この関数は、

  • 「register_setting()」で「wporg」ページに新規設定を登録します。
  • 「add_settings_section()」で「wporg」ページに新しいセクションを登録します。
  • 「add_settings_field()」で「wporg」ページ内の「wporg_section_developers」セクションに新しいフィールドを登録します。

まずは、管理ページを登録して表示できるようにします。

/**
 * Register our wporg_options_page to the admin_menu action hook.
 */
add_action( 'admin_menu', 'wporg_options_page' );

HTMLを出力するPHPコードは「wporg_options_page_html」関数に定義します。

/**
 * Add the top level menu page.
 */
function wporg_options_page() {
    add_menu_page(
        'WPOrg',
        'WPOrg Options',
        'manage_options',
        'wporg',
        'wporg_options_page_html'
    );
}

HTMLを出力する関数です。

/**
 * Top level menu callback function
 */
function wporg_options_page_html() {
    // check user capabilities
    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }

    // add error/update messages

    // check if the user have submitted the settings
    // WordPress will add the "settings-updated" $_GET parameter to the url
    if ( isset( $_GET['settings-updated'] ) ) {
        // add settings saved message with the class of "updated"
        add_settings_error( 'wporg_messages', 'wporg_message', __( 'Settings Saved', 'wporg' ), 'updated' );
    }

    // show error/update messages
    settings_errors( 'wporg_messages' );
    ?>
    <div class="wrap">
        <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
        <form action="options.php" method="post">
            <?php
            // output security fields for the registered setting "wporg"
            settings_fields( 'wporg' );
            // output setting sections and their fields
            // (sections are registered for "wporg", each field is registered to a specific section)
            do_settings_sections( 'wporg' );
            // output save settings button
            submit_button( 'Save Settings' );
            ?>
        </form>
    </div>
    <?php
}

画面が表示できたら、設定を行う関数を登録します。

/**
 * Register our wporg_settings_init to the admin_init action hook.
 */
add_action( 'admin_init', 'wporg_settings_init' );

「wporg_settings_init」関数は下の関数です。以下の3つの処理を行っています。
・「register_setting( 'wporg', 'wporg_options' );」でオプション登録を行います。→調査中

/**
 * custom option and settings
 */
function wporg_settings_init() {
    // Register a new setting for "wporg" page.
    register_setting( 'wporg', 'wporg_options' );

    // Register a new section in the "wporg" page.
    add_settings_section(
        'wporg_section_developers',
        __( 'The Matrix has you.', 'wporg' ), 'wporg_section_developers_callback',
        'wporg'
    );

    // Register a new field in the "wporg_section_developers" section, inside the "wporg" page.
    add_settings_field(
        'wporg_field_pill', // As of WP 4.6 this value is used only internally.
                                // Use $args' label_for to populate the id inside the callback.
            __( 'Pill', 'wporg' ),
        'wporg_field_pill_cb',
        'wporg',
        'wporg_section_developers',
        array(
            'label_for'         => 'wporg_field_pill',
            'class'             => 'wporg_row',
            'wporg_custom_data' => 'custom',
        )
    );
}

ここからはもちょっと調査してから記載ます。。。

基本的なフック

基本的なフックは下のモノらしいです。

  1. register_activation_hook(): プラグインをアクティブ化すると、アクティベーション フックが実行されます。
  2. register_deactivation_hook(): プラグインが非アクティブ化されると、非アクティベーション フックが実行されます。
  3. register_uninstall_hook (): WordPress 管理画面内の削除リンクをクリックした場合、プラグインはアンインストールされたとみなされます。

上記のフックが基本になっているようです。それぞれのタイミング(プラグインのアクティブ化、非アクティブ化、削除)でそれぞれの処理を行うように実装することができます。

プラグインで使用するフックAPIのリファレンスはこちらです。

register_action_hookのサンプル

/* Main Plugin File */
...
/** プラグイン起動時のスクリプト */
function my_plugin_activate() {

  add_option( 'Activated_Plugin', 'Plugin-Slug' );

  /* activation code here */
}
// ここでプラグインを有効にした時の処理を実行する
register_activation_hook( __FILE__, 'my_plugin_activate' );

/** プラグインロード時の処理 */
function load_plugin() {

    if ( is_admin() && get_option( 'Activated_Plugin' ) == 'Plugin-Slug' ) {

        delete_option( 'Activated_Plugin' );

        /* do stuff once right after activation */
        // example: add_action( 'init', 'my_init_function' );
    }
}
// プラグイン
add_action( 'admin_init', 'load_plugin' );
「admin-init」のタイミングについて

以下のような記載がありました。

これはユーザー向けの管理画面でのみ実行されるわけではないことに注意してください。
admin-ajax.php および admin-post.php でも実行されます。

register_uninstall_hook()

以下のサンプルコードは、プラグインを削除するときに使用するフックです。書き方は下のようなものです。

<実装方法、その1>
これは、フックを追加する形の実装方法です。

register_uninstall_hook(
    __FILE__,
    'pluginprefix_function_to_run'// 削除時に実行するメソッド
);

<実装方法、その2>
これは、作成したプラグインフォルダに「uninstall.php」を作成することで実行することができます。

// if uninstall.php is not called by WordPress, die
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
    die;
}

$option_name = 'wporg_option';

delete_option( $option_name );

// for site options in Multisite
delete_site_option( $option_name );

// drop a custom database table
global $wpdb;
$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}mytable" );

フックの追加方法

do_action()を使用してフックを追加、拡張できます。
具体的には、下のようにコードを書きます。

  • example_callback: コールバックメソッド
  • example_action: アクションの名前
// アクションでコールバックされるメソッド
function example_callback( $arg1, $arg2 ) {
    // (maybe) do something with the args.
}
// アクション(メソッド)の追加
add_action( 'example_action', 'example_callback', 10, 2 );

/*
 * アクションの実行=追加したフックを実行する
 * - 'example_action' is the action hook.
 * - $arg1 and $arg2 are the additional arguments passed to the callback.
 */
do_action( 'example_action', $arg1, $arg2 );

プラグインフォルダ作成のまとめ

プラグインを作成するときには、次のようにやることが推奨されている。
※ A. 「/」をワードプレスのルート・ディレクトリとする。
  B. 作成するプラグインを「CustomQuestionary」とする。

  1. /wp-content/pluginディレクトリに「CustomQuestionary」フォルダを作成する。
  2. register_activation_hook()はプラグインを有効化したときに起動するメソッドを登録する。
  3. register_deactivation_hook()はプラグインを無効化したときに起動するメソッドを登録する。
  4. register_uninstall_hook ()はプラグインをアンインストールしたときに起動するメソッドを登録する。
  5. add_action()はWordPress コアが実行中の特定のタイミング、または特定のイベントの発生時に起動する。
  6. do_action()は登録したアクション(フック)を起動する。
  7. remove_action()は登録したアクション(フック)を削除する。

次は以下の項目を記載します。。。

PHPファイルを作成する

上記で、プラグインのある程度の作成方法を学習したのでそれを実践します。

プラグインPHPを作成する

今回、作成するプラグインは下のような名前のプラグインです。

CustomQuestionary

下のようにファイルを作成しました。他にもファイルがありますが、ここでは、「CustomQuestionary.php」に注目していただきたく思います。

コードを書いてみる

早速コードを書いていきましょう。その前に、基本的なフックとして下の関数を挙げましたが、実行しないのに次のような結果になりました。

下のフックは追加してないが。。。

筆者が試したところ、「register_activation_hook()」と「register_deactivation_hook()」は実行していないけど、プラグインの表示非表示はできているようです。

プラグイン有効 プラグイン無効

代わりにこちらを実行

プラグイン名.php(CustomQuestionary.php)には次のコードを実装しています。

/********************************************************
 * ダッシュボードに追加するための関数(プラグイン有効時) *
 ********************************************************/
function addCustomQuestionary() {
    // ダッシュボードにこの表示が出るように追加する
    add_menu_page( 'Test Plugin', 'CustomQuestionary', 'manage_options' , 'test-plugin' , 'helloCustomQuestionary' );
    // 投稿記事にアンケートを表示するスクリプトをリンクする
    add_action( 'wp_enqueue_scripts', 'insertQuestionary' );
}

/******************************
 * アクションフックを追加する *
 ******************************/
add_action('admin_menu', 'addCustomQuestionary' );
add_action('wp_enqueue_scripts', 'insertQuestionary' );
do_action( 'addCustomQuestionary' );

コードの内容としては、次のようなことを行っております。

  1. ダッシュボードに追加するための関数(プラグイン有効時)を定義
  2. この関数では、ダッシュボードに子のプラグインが表示されるようにフックを登録
  3. 「insertQuestionary()」(PHPでJSを出力する関数)で定義しているJSをフックに登録
  4. アクションフック「addCustomQuestionary」を実行

add_menu_page()関数について

add_menu_page( string $page_title , string $menu_title , string $capability , string $menu_slug
, callable $callback = ” , string $icon_url = ” , int|float $position = null ): string

< 説明 >

この関数は、ページがメニューに含まれるかどうかを決定するために使用される機能を受け取ります。
ページの出力を処理するためにフックされる関数は、ユーザーが必要な機能を持っているかどうかもチェックする必要があります。

<パラメーター>

※required=必須, optional=任意

パラメータ名 データ型 必須
$page_title String required

メニューが選択されたときにページのタイトルタグに表示されるテキスト。

パラメータ名 データ型 必須
$menu_title String required

メニューに使用されるテキスト。

パラメータ名 データ型 必須
$capability String required

このメニューをユーザーに表示するために必要な機能。

パラメータ名 データ型 必須
$menu_slug String required

このメニューを参照するスラッグ名。このメニュー ページに対して一意である必要があり、互換性のある小文字の英数字、ダッシュ、およびアンダースコア文字のみを含める必要がありますsanitize_key() 。

パラメータ名 データ型 必須
$callback メソッド optional

このページのコンテンツを出力するために呼び出される関数

パラメータ名 データ型 必須
$icon_url String optional
  • このメニューに使用されるアイコンの URL。データ URI を使用して、base64 でエンコードされた SVGを渡します。
  • データ URI は、配色に合わせて色付けされます。これは で始まる必要があります'data:image/svg+xml;base64,'。
  • フォント アイコンを使用するには、Dashcons ヘルパー クラスの名前を渡します'dashicons-chart-pie'。
  • div.wp-menu-image を空のままに渡すと'none'、CSS 経由でアイコンを追加できるようになります。
パラメータ名 データ型 必須
$position int or float optional

この項目が表示されるメニュー順序内の位置。

プラグインの定義

まずは、プラグインの説明や、有効・無効の表示部分を実装します。

コメントで作る

ズバリ、コメントで定義できるようです。

/*
Plugin Name: CustomQuestionaryPlugin
Plugin URI: (プラグインの説明と更新を示すページの URI)(未決定)aaa
Description: アンケートを作成、ブログ記事の中に埋め込むことができ、集計結果をダッシュボードで確認ができる。
Version: 1.0
Author: ZenryokuService
Author URI: https://zenryokuservice.com/
License: GPL2
*/

そしてライセンスに関しても、どこからかこぴったものを修正して使用しました。

/*****************************
 *      License              *
 *****************************/
 /*  Copyright 2020 ZenryokuService
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License, version 2, as
    published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

コメント定義の詳細

名前 説明
プラグイン名 (必須項目) WordPress Admin のプラグイン リストに表示されるプラグインの名前。
プラグイン URI プラグインのホームページ。できれば独自の Web サイト上にある一意の URL である必要があります。これはプラグインに固有のものである必要があります。ここでは WordPress.org URL を使用できません。
説明 WordPress Admin の「プラグイン」セクションに表示されるプラグインの短い説明。この説明は 140 文字未満にしてください。
バージョン プラグインの現在のバージョン番号 (1.0 や 1.0.3 など)。少なくとも次のものが必要です:プラグインが動作する最低の WordPress バージョン。
PHP が必要 最低限必要な PHP バージョン。
作成者 プラグインの作成者の名前。複数の著者をカンマを使用してリストすることもできます。
著者 URI 著者の Web サイトまたは別の Web サイト上のプロフィール (WordPress.org など)。
License プラグインのライセンスの短縮名 (スラッグ) (GPLv2 など)。ライセンスの詳細については、WordPress.org のガイドラインを参照してください。
ライセンス URI ライセンスの全文へのリンク (例: https://www.gnu.org/licenses/gpl-2.0.html )。
テキスト ドメイン プラグインのgettextテキストドメイン。詳細については、「プラグインの国際化方法」ページの「テキスト ドメイン」セクションを参照してください。
ドメイン パス ドメイン パスにより、WordPress は翻訳の場所を知ることができます。詳細については、「プラグインの国際化方法」ページの「ドメイン パス」セクションを参照してください。
ネットワーク プラグインがネットワーク全体でのみアクティブ化できるかどうか。trueにのみ設定でき、不要な場合は省略する必要があります。
URI の更新 サードパーティのプラグインが、WordPress.org プラグイン ディレクトリにある同様の名前のプラグインの更新で誤って上書きされることを回避できます。詳細については、関連する開発ノートを参照してください。

<サンプルコード>

/*
 * Plugin Name:       基本的なプラグイン
 * Plugin URI:        https://example.com/plugins/the-basics/
 * Description:       基本的なプラグインを操作する.
 * Version:           1.10.1
 * Requires at least: 5.1
 * Requires PHP:      7.1
 * Author:            たくのじ
 * Author URI:        https://takunoji.example.com/
 * License:           GPL v2 or later
 * License URI:       https://zenryokuservice.com/wp/%e3%83%97%e3%83%a9%e3%82%a4%e3%83%90%e3%82%b7%e3%83%bc%e3%83%9d%e3%83%aa%e3%82%b7%e3%83%bc/
 * Update URI:        https://zenryokuservice.com/wp/%e3%83%97%e3%83%a9%e3%82%a4%e3%83%90%e3%82%b7%e3%83%bc%e3%83%9d%e3%83%aa%e3%82%b7%e3%83%bc/
 * Text Domain:       test-plugin
 * Domain Path:       /languages
 */

自作要件について

ここで、プログラムの設計を行います。必要な機能要件としては以下のものとします。

  1. プラグインを有効にしたら、WP管理画面にアンケートを作成して表示、編集ができる
  2. アンケートを作成しDBでアンケートを管理、クリック数をカウントする
  3. アンケートは質問と回答(選択式)をセットにして1つずつ独立させる
  4. アンケートは回答以外に、クリックされた時間、ページ(URL)の情報も取得する

機能の一覧

上記の各要件に対して、それらを実現するための機能を一覧化します。

WP管理画面にアンケートを作成して表示、編集ができる

<機能一覧>

  • 管理画面は、使い方「HELP]と登録済みのアンケートを表示する。
    ※各アンケートは統計学で使用する相関係数が「0.5(修正可能)」以上のものを関連表示させる(※仕様検討中)

  • アンケートは「質問」、回答1~5までを入力して、DBに登録する

これらの機能を実装するのに「manage.php」と「index.js」の2ファイルを作成しました。

  • manage.php: プラグインの画面を開いたときに表示する画面(HTML)を出力
  • index.js: 上記で出力した画面で使用するJSを定義

作成した画面のコード

<?php
ini_set('display_errors', "On");

function convert($str) {
    if (isEmpty($str)) {
        "";
    }
    return $str;
}

function _handle_form_action(){
    $insertSQL = "INSERT INTO `QUESTIONARY`(`question`, `answer1`, `answer2`, `answer3`, `answer4`, `answer5`, `html_class`, `html_style`) VALUES (";

    $keys = array('question', 'ans1', 'ans2', 'ans3', 'ans4', 'ans5', 'hrml_class', 'html_style');

    $insertSQL .= "'" . convert($_POST[$keys[0]]) . "',";
    $insertSQL .= "'" . convert($_POST[$keys[1]]) . "',";
    $insertSQL .= "'" . convert($_POST[$keys[2]]) . "',";
    $insertSQL .= "'" . convert($_POST[$keys[3]]) . "',";
    $insertSQL .= "'" . convert($_POST[$keys[4]]) . "',";
    $insertSQL .= "'" . convert($_POST[$keys[5]]) . "',";
    $insertSQL .= "'" . convert($_POST[$keys[6]]) . "',";
    $insertSQL .= "'" . convert($_POST[$keys[7]]) . "'";
    $insertSQL .= ");";

    $res = null;

    global $wpdb;

    try {

        $res = $wpdb->query($insertSQL);
    } catch (e) {
        $res =  $insertSQL . "\r\n";
        $res .= e.getMessage();
        echo  $res . $wpdb->last_error;
    } finally {
        wp_die();
    }
}

function _no_handle_form_action() {

}

$pluginRoot = str_replace('\\', '/', plugin_dir_path( __FILE__ ));
// DB登録用のPHPファイルへのURL
$insertUrl = 'http://localhost/wp/wp-admin/admin-ajax.php';
// DB削除用のPHPファイルへのURL
$deleteUrl = admin_url('admin-ajax.php');
$pageCount = 0; //$_SESSION['pageCount']+1;

// AJAX ハンドラを AJAX アクションに登録(ログインユーザー用)
add_action('wp_ajax_my_action', '_handle_form_action');
// AJAX ハンドラを AJAX アクションに登録(非ログインユーザー用)
add_action('wp_ajax_nopriv_my_action', '_no_handle_form_action');

global $wpdb;
$dataCount = $wpdb->get_var('SELECT count(question_id) FROM QUESTIONARY');

$func = <<<EOM
function getPageCount() {
    return $pageCount;
}
EOM;
echo '<script>' . $func . '</script>';

?>

<h1>Custom Questionary Plugin</h1>

<hr>
<div class="container">
    <details>
        <summary>Help</summary>
        <div class="row">
            <div class="col">
                <dl>
                    <dt><h4>Usage(使い方)</h4></dt>
                    <dd>1.Create Questions(質問を作成します)</dd>
                    <dd>2.Create answers(回答を作成します): <button type="button" class="btn-sm btn-primary">項目追加</button></dd>
                    <dd>3.Set position(設置する場所を指定します)</dd>
                </dl>
            </div>
            <div class="col">
                <dl>
                    <dt><h4>Usage2(使い方2)</h4></dt>
                    <dd><button type="button" class="btn-xs btn-success">作成</button>: Create sample form</dd>
                    <dd><button type="button" class="btn-xs btn-warning" onclick="deleteForm()">削除</button>: Delete form</dd>
                    <dd><input type="checkbox"/>: Checked -> clear all forms in this page</dd>
                </dl>
            </div>
        </div>
        </details>
    <?php if ($dataCount > 0) { ?>
        <hr>
        <details>
            <summary class="text-success">QuestionTable</summary>
            <div class="row">
                <div class="col">
                    <b class="text-info">Questionaries(質問一覧)</b>
                    <table id="qestionTable" class="table">
                        <thead>
                            <tr>
                                <th>#</th>
                                <th>質問(Question)</th>
                                <th>回答1(ans1)</th>
                                <th>回答2(ans2)</th>
                                <th>回答3(ans3)</th>
                                <th>回答4(ans4)</th>
                                <th>回答5(ans5)</th>
                                <th>挿入先</th>
                            </tr>
                        </thead>
                        <tbody>
                        <?php
                            $result = $wpdb->get_results('SELECT * FROM QUESTIONARY', ARRAY_A);
                            // ここから下はデータがある時のみ表示
                            $recordCount = 0;
                            foreach($result as $key => $data) {
                                echo '<tr data-qid="' . $data['question_id'] . '">';
                                echo '<td><input type="radio" name="dataRecord" value="' . $recordCount . '"/></td>';
                                echo '<td>' . $data['question'] . '</td>';
                                echo '<td>' . $data['answer1'] . '</td>';
                                echo '<td>' . $data['answer2'] . '</td>';
                                echo '<td>' . $data['answer3'] . '</td>';
                                echo '<td>' . $data['answer4'] . '</td>';
                                echo '<td>' . $data['answer5'] . '</td>';
                                echo '<td>' . $data['html_class'] . '</td>';
                                echo '</tr>';
                                $recordCount++;
                            }
                        ?>
                        </tbody>
                    </table>
                    <!-- 編集ボタン一式 -->
                    <button onclick="getTableRecord()">Remove(削除)</button>
                </div>
            </div>
        </details>
    <hr>
    <?php
        }
    ?>
    <hr>
    <h3>Create Question(質問作成)</h3>
    <hr>
    <h4>== Control forms ==</h4>
    <div class="row">
        <div class="col-sm-3 text-primary">・Add answers:<button type="button" class="btn-xs btn-primary" onclick="addRow(this)">項目追加</button></div>
        <div class="col-sm-3 text-success">・Create form:<button type="button" class="btn-xs btn-success" onclick="createForm()">作成</button></div>
        <div class="col-sm-3 text-warning">・Delete form:<button type="button" class="btn-xs btn-warning" onclick="deleteForm()">削除</button></div>
    </div>
    <div class="row">
        <div class="col-sm-3 text-danger">・Insert into DB:<button id="insertDbBtn" type="button" class="btn-xs btn-danger" onclick="outputForm()">登録</button></div>
        <div class="col-sm-3">・Clear Input form:<input type="checkbox" onclick="delInputForm()"/></div>
    </div>
    <h4>== Input forms ==</h4>
    <table id="questionTable">
        <tr>
            <td>
                Insert Position:
            </td>
            <td>
                <select id="insertPosSelect" onchange="inputInsertPos(this)">
                    <option selected></option>
                    <option value="site-navigation">site-navigation</option>
                    <option value="main">main</option>
                    <option value="reply-title">reply-title</option>
                    <option value="primary">primary</option>
                    <option value="comments">comments</option>
                    <option value="respond">respond</option>
                    <optopm vaiue="main">main</option>
                </select>
                <input id="insertPos" type="text" maxlength="30" size="35" placeholder="挿入場所を記入します"/>
            </td>
        </tr>
        <tr>
            <td>
                Input Question:
            </td>
            <td>
                <input id="questionMessage" type="text" maxlength="30" size="35" placeholder="質問内容を記入します"/>
            </td>
        </tr>
        <tr>
            <td>
                Input Answer:
            </td>
            <td>
                <input id="ansText0" data-ans="0" type="text" maxlength="12" size="12"/>
            </td>
        </tr>
    </table>
    <hr/>
    <h3>Sample</h3>
    <div id="result"/>
</div>

ディレクトリのパス取得関数

こちらのページに記述がありました。大まかには下のような関数が使えるようです。

プラグインフォルダのファイル参照

以下のコードは「myscript.js」ファイルへのパスを取得します。

plugins_url( 'myscript.js', __FILE__ );

他にも、下のようにパスを取得できる関数があります。
<プラグディレクトリへのパス>

plugins_url()
plugin_dir_url()
plugin_dir_path()
plugin_basename()

<テーマへのパス>

get_template_directory_uri()
get_stylesheet_directory_uri()
get_stylesheet_uri()
get_theme_root_uri()
get_theme_root()
get_theme_roots()
get_stylesheet_directory()
get_template_directory()

WordPressの定数

ワードプレスで定義されている定数です。

WP_CONTENT_DIR  // 末尾のスラッシュなし、フルパスのみ
WP_CONTENT_URL  // URL全体
WP_PLUGIN_DIR  // フルパス、末尾のスラッシュなし
WP_PLUGIN_URL  //完全な URL、末尾のスラッシュなし

// MS ではデフォルトで利用可能ですが、単一サイトのインストールでは設定されません
// 単一サイトのインストールで使用できます (通常どおり、自己責任で)
UPLOADS // 設定されている場合、ABSPATH を基準にしてフォルダーをアップロードします (例: /wp-content/uploads)

HttpGET関数の使い方

つまりは、httpリクエストでHTMLなどを取得する方法です。
参照サイトはこちらです。

$response = wp_remote_get( '取得したいHTMLへのURL' );

「$response」には、対象のページのHTML文書がセットされています。
レスポンスのサンプルです。

Array(
    [headers] => Array(
        [server] => nginx
        [date] => Fri, 05 Oct 2012 04:43:50 GMT
        [content-type] => application/json; charset=utf-8
        [connection] => close
        [status] => 200 OK
        [vary] => Accept
        [x-ratelimit-remaining] => 4988
        [content-length] => 594
        [last-modified] => Fri, 05 Oct 2012 04:39:58 GMT
        [etag] => "5d5e6f7a09462d6a2b473fb616a26d2a"
        [x-github-media-type] => github.beta
        [cache-control] => public, s-maxage=60, max-age=60
        [x-content-type-options] => nosniff
        [x-ratelimit-limit] => 5000
    )
    [body] => {"type":"User","login":"blobaugh","gravatar_id":"f25f324a47a1efdf7a745e0b2e3c878f","public_gists":1,"followers":22,"created_at":"2011-05-23T21:38:50Z","public_repos":31,"email":"ben@lobaugh.net","hireable":true,"blog":"http://ben.lobaugh.net","bio":null,"following":30,"name":"Ben Lobaugh","company":null,"avatar_url":"https://secure.gravatar.com/avatar/f25f324a47a1efdf7a745e0b2e3c878f?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png","id":806179,"html_url":"https://github.com/blobaugh","location":null,"url":"https://api.github.com/users/blobaugh"}
    [response] => Array(
        [preserved_text 5237511b45884ac6db1ff9d7e407f225 /] => 200
        [message] => OK
    )
    [cookies] => Array()
    [filename] =>
)

wp_remote_retrieve_body()メソッドでBODYのみを取得することができます。

$response = wp_remote_get( 'https://api.github.com/users/blobaugh' );
$body     = wp_remote_retrieve_body( $response );

Http POSTの使い方

wp_remote_post()を使用します。

実行する方法は下のように実行します。

$response = wp_remote_post( 'http://your-contact-form.com', $args );

$argsに関しては、下のように定義できます。

$args = array(
    'body'        => $body,
    'timeout'     => '5',
    'redirection' => '5',
    'httpversion' => '1.0',
    'blocking'    => true,
    'headers'     => array(),
    'cookies'     => array(),
);

Ajaxの使い方

参照サイトはこちらです。

課題

ここまでで、クライアント側=画面で表示している部分の作成はできたのですが、DBのデータを更新する処理が実装できていません。
JSからPHPへリクエスト(submitを含む)が送信できていない状態です。

ここの部分を解決する必要があります。。。