WordPress ウィジェットでAjaxを使う:通信編

前回、WordPress ウィジェットでAjaxを使う:潜入編 で、WordPress からブラウザへ JavaScript のスクリプトコードとデータを渡すところまで行ったので、今回は jQueryを使って WordPress に Ajax でデータの送受信を行なってみます

jQueryとPHP間でAjax通信をさせる方法を検索すると沢山ヒットするのですが、WordPressを使っている場合には、一般的に紹介されているPHPとJavaScript間の通信処理よりも、プログラム間で連携を取りやすくなるように工夫されています

WordPressでAjaxを使う時に、ちょっとした仕掛けを施すことで、通信先のURLで実行させる専用のPHPファイルを用意することなく、プラグイン内の関数が指定出来るようになります

手順

  1. プラグインプログラム内に情報を受信する関数を用意します
  2. 受信時のキーワードを決め、キーワードと受信関数を登録します
  3. jQuery がキーワードを使い情報を送信する
  4. ajaxによる受信処理とコンテンツ更新の確認

受信関数を用意する

ウィジェットプログラムの Is_Mobile_Text クラス内に受信関数 is_mobile_textout() を作成

受信関数では、次の処理を行います

  • ページ内で表示される is_mobile_text_widget の表示幅(px)を取得
  • 取得した表示幅データが、最小、最大幅条件に一致していればコンテンツを表示する

但し、複数のウィジェットが使用されることを考慮する必要があります
ウィジェット毎にオプションデータの有効幅と取得したウィジェット幅のデータを比較して、結果を json 形式の識別IDとコンテンツの組み合わせデータとしてブラウザへ出力します

作成した関数は、こんな感じです

    public function is_mobile_textout()
    {
        if(isset($_POST['imt_width'])){
            $ajaxdata = array();
        
            $instance = get_option($this->option_name);
            $id_nums = array_filter( array_keys( $instance), 'is_int');
            foreach((array) $id_nums AS $number){
                if(!empty($number) && is_numeric($number)){

                    //ajax から送られてきたウィジェット番号と照合
                    if(!empty($_POST['imt_width'][$number])){
                        $width = (int)$_POST['imt_width'][$number];
                        
                        //ウィジェット幅が出力条件に一致しているか?
                        if($instance[$number]['smallest'] <= $width && $width <= $instance[$number]['largest'] ){
                            $outtext = $instance[$number]['cmtext'];
                            $outtext .= "ウィジェット幅は" . $width . " px です";
                            if(!empty( $filter )){
                                $outtext = wpautop( $outtext );
                            }
                        }
                        else {
                            $outtext = "";
                        }
                        //jQuery 側で選択するためのIDキーを付ける
                        $ajaxdata["#$this->id_base-$number"] = $outtext;
                    }
                }
            }
            if(!empty($ajaxdata)){
                echo json_encode($ajaxdata), PHP_EOL;
            }
        }
        exit;
    }
ウィジェットのインスタンスとオプションデータ

ここで、ウィジェットプログラムのオプションデータについて補足しておきます

通常、ウィジェットは、複数使用することが出来ますが、他のウィジェットの情報をアクセスすることはありませんので、ウィジェット毎に widget( $args, $instance ) 関数から自分のオプションデータを $instance インスタンスとして使用出来るようになっています

今回は、複数のウィジェットを使用している場合に、jQuery、ウィジェットプログラムの双方でウィジェット毎にID番号からウィジェットを識別する必要があります

ウィジェットプログラムで他のウィジェットのオプションデータを取得するには、get_option($this->option_name) を使用します

例えば、ウィジェットを3個使用しているとID番号ごとのデータを全て取得出来ます

各々のオプションデータには、2次元配列として簡単にアクセス出来るようになっています

Widget_option

キーワードを決め、受信関数を登録

次にキーワードを決めます。今回は、 “IMTrequest” とします

WordPress 側

is_mobile_text_widget プラグインのコンストラクタに次の2行を加えます

        //ログインユーザー、ログインしていないユーザーの両方でアクションフックで実行する関数名を登録
        add_action('wp_ajax_nopriv_IMTrequest', array(&$this, 'is_mobile_textout'));
        add_action('wp_ajax_IMTrequest',        array(&$this, 'is_mobile_textout'));

登録は、ログインユーザー(wp_ajax_ …)とログインしていないユーザー(wp_nopriv_ajax_ …)用に各々行う必要があります

“IMTrequest” というキーワード文字列と組み合わせたアクションフックを作成して、受信関数is_mobile_textout を登録します

  • wp_ajax_nopriv_IMTrequest
  •  wp_ajax_IMTrequest

但し、まだアクションフックに登録しただけなので、この関数を実行するためには JavaScript 側の協力が必要です

また、この後で、ajax動作を確認するために widget 関数を少し修正しておきます

widget実行時に、コンテンツを出力せずにタグのみを出力して、対象ウィジェットでのタグ名とID番号を wp_localize_script 関数でセットします

    function widget( $args, $instance ) {

        if(empty($_POST['imt_width'])){
            //連想配列 $args を変数名($before_widget, $before_title, $after_title, $after_widget, ...)に展開
            extract($args);

            //値がない項目に対して引数で指定した初期値を設定
            $default  = array( 'title' => '', 'cmtext' => '', 'filter'=> FALSE, 'hidetitle'=> FALSE, 'smallest' => 0, 'largest' => 9999 );
            $instance = wp_parse_args( (array) $instance,  $default);

            $title = $instance['title'];
            $hide  = $instance['hidetitle'];
            $filter= $instance['filter'];
            $cmtext= $instance['cmtext'];

            //Javascript に渡すデータを更新
            //設置数に応じたウィジェットのIDを配列で渡す
            $id_base = $this->id_base;
            $id_nums = array_filter( array_keys( get_option($this->option_name)), 'is_int');
            wp_localize_script('IMT-ajax-handle', 'is_mobile_text_ajax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'widget_id' => $id_base, 'id_nums' => $id_nums) );

            echo $before_widget;
        
            if ( !empty( $title ) && empty( $hide )) {
                echo $before_title . $title . $after_title;
            }
            //ajax 出力用のタグのみ先に用意する
            ?><div class="textwidget">><?php //echo !empty( $instance['filter'] ) ? wpautop( $text ) : $text; ?></div><?php

            echo $after_widget;
        }

キーワードを使い情報を送信

JavaScript側

jQuery スクリプトコードの ajax の data の ”action” キーに対して、先ほど決めたキーワード “IMTrequest” をセットします

        $.ajax({
            type: 'POST',
            url: is_mobile_text_ajax.ajaxurl,
            data: {
                "action"    : "IMTrequest",
                "imt_width" : width
            },
            dataType: 'json',

WordPress では、POST 先のURLは、admin-ajax.php となります

プラグイン側から wp_localize_script 関数により、事前に ajaxurl として設定されているので、そのURLを使用します

wp_localize_script('IMT-ajax-handle', 'is_mobile_text_ajax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'widget_id' => "", 'id_nums' =>"" ) );

WordPress側のアクションフックを動作させる仕組み

POSTデータ中の action と キーワードが、送信先の admin-ajax.php で処理され、do_action によりアクションフックに登録されている wp_ajax_nopriv_IMTrequest, wp_ajax_IMTrequest がフックされ is_mobile_textout 関数が実行されます

従って、action とキーワードを記述しないと受信されないので注意です (^^)

送信データ情報

data 部には、送信データも json 形式で登録します

json 形式を用いるのは、データの受け渡しが楽に行うことが出来るからです

ここでは、wp_localize_script 関数により通知された、widget_id(ウィジェットのベース名)と id_nums(ID番号の配列)を使いウィジェットのタグの幅データを取得して、data に imt_width というデータキー名でセットします

例えば、ベース名が “is_mobile_text” で、IDが [3] とセットされていれば、 “#is_mobile_text-3 .textwidget” という、is_mobile_text-3 ID内の textwidget クラスタグの幅 width() を取得します。複数のIDが指定されていれば、その全てのIDに対して同様にタグの幅を取得します

これで、キーワード “IMTrequest” を使うことで、アクションフックにより、関数 is_mobile_textout とダイナミックに紐付けして、 受信処理させるということが出来ます

なかなか巧妙な手法です (^^)

WordPress側では、$_POST[‘imt_width’] と言う形で受信したデータを扱うことが出来ます

また、スクリプト側からも json 形式でデータを送信しているので、この $_POST[‘imt_width’] データは、自動的に連想配列として展開されID別に簡単にアクセスすることが出来ます

ajaxによる受信処理とコンテンツ更新確認

今までのコードが上手く動作すれば、簡単に確認することが出来ます

  1. WordPress の管理画面から、is mobile text widget を有効化します
  2. 管理画面の外観→ウィジェットを開き、表示させたいサイドバーに is_mobile テキストウィジェットを配置します
  3. 有効ウィジェット幅の最小、最大を適当にセットして、テキスト部へ適当な文章や画像リンクを貼り付けます
  4. 後は、通常どうりサイトを表示させれば、ウィジェットの表示幅に応じて表示されたり、されなかったりすることが確認出来ます

下図は、ウィジェットを3つ配置して、標示条件を変えことで is_mobile test3 のコンテンツが表示されていない様子です

SnapCrab_NoName_2013-6-17_18-57-8_No-00

ちなみに、このサンプルコードではリサイズには対応していないので、レスポンシブなテーマを使用していてブラウザの幅を変えてみてもダイナミックには変化しません。再ロードさせる必要があります

以上、WordPress での Ajax 処理の使い方のサンプルコードを紹介しました

なかなか、うまく説明出来ませんでしたが、NetBeansとChromeを使って、ブレイクさせてデータを確認すれば理解しやすくなると思います

今回、JavaScript(jQuery) を初めて使ってみましたが、見よう見まねで ajax で通信を行わせることが出来ました。また、複数のウィジェットのオプションデータを get_option 関数で取得できることがわかったのが収穫です

最後に、今回の作業では、主に下記サイトを参考にさせて頂きました。感謝です

セキュリティ上の制限もありますが、いろいろと応用できそうな気がします。では (^^)


まとめ記事紹介

search star user home refresh tag chevron-left chevron-right exclamation-triangle calendar comment folder thumb-tack navicon angle-double-up angle-double-down angle-up angle-down quote-left googleplus facebook instagram twitter rss