質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.36%

  • PHP

    22456questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • JavaScript

    18718questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • WordPress

    8220questions

    WordPressは、PHPで開発されているオープンソースのブログソフトウェアです。データベース管理システムにはMySQLを用いています。フリーのブログソフトウェアの中では最も人気が高く、PHPとHTMLを使って簡単にテンプレートをカスタマイズすることができます。

  • jQuery

    7519questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

  • Ajax

    1225questions

    Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。

「Ajaxの中にAjax」は正しい処理ですか?

受付中

回答 4

投稿 編集

  • 評価
  • クリップ 3
  • VIEW 404

chacky

score 4

前提・実現したいこと

AjaxでのWordpress投稿システムの実装において、投稿後にその内容を表示させられないという問題が発生しました。

下記「該当のソースコード」にあるように、single.php を読むときに、投稿できている情報を使ってくれないという状況です。

自分なりの解決策として、下記「試したこと」にあるように、「Ajaxの中にAjax」という方法を考えたのですが、これは適切な方法ですか?

独学で不安なので、より適切な方法での実装を実現したいと思い質問させて頂きました。
宜しくお願いします。

該当のソースコード

まずこちらのPHPですが、
include locate_template( 'template-parts/single.php' );
と書いても、投稿後にその内容を表示させられないという問題が発生しました。(最後から12行目の部分です)

/* nonceを出しておく */    
add_action( 'wp_enqueue_scripts', 'my_enqueue_scripts' );
function my_enqueue_scripts() {
    $handle_post_new = 'my_script_post_new';      
    $jsFile_post_new= 'path/to/myscript_post_new.js';
    wp_register_script($handle_post_new, $jsFile_post_new, ['jquery']);
    $action_post_new= 'my_ajax_action_post_new';
    wp_localize_script($handle_post_new, 'MY_AJAX_post_new', [
        'api'    => admin_url( 'admin-ajax.php' ),
        'action' => $action_post_new,
        'nonce'  => wp_create_nonce( $action_post_new ),
    ]);
    wp_enqueue_script($handle_post_new);            
}

/* 投稿する */
add_action( 'wp_ajax_my_ajax_action_post_new', 'my_ajax_event_post_new' );
function my_ajax_event_post_new() {

    $action_post_new = 'my_ajax_action_post_new';    

    // nonceがただしい
    if( check_ajax_referer($action_post_new, 'nonce', false) ) {

        // データ受け取り
        $post_new_title = esc_html( $_POST['post_new_title'] );
        $post_new_content = strip_tags( $_POST['post_new_content'], "<br>" );
        $post_new_meta_img = esc_html( $_POST['post_new_meta_img'] );

        // データ更新
        $post_value = array(
            'post_type'    => 'post',
            'post_author'  => get_current_user_id(),
            'post_title'   => $post_new_title,
            'post_content' => $post_new_content,
        );
        $insert_id = wp_insert_post($post_value); // 投稿してそのIDを取得
        if($insert_id) {
            update_post_meta($insert_id, 'post_meta_img', $post_new_meta_img);
        } else {
            die('失敗しました。');        
        }

        // 出力
        include locate_template( 'template-parts/single.php' );

    }
    // nonceがおかしい
    else {

        die('失敗しました。');        

    }

    die();
}


ちなみにjQueryはこうです。
「.container」の中身を、新しい投稿内容を使った single.php に入れ替えることが目的でした。

$(document).on("click",".post_submit", function(){        

    var post_new_area = $('.container');
    var post_new_title = $('#post_new_title').text();
    var post_new_content = $('#post_new_content').html();
    var post_new_meta_img = $('#post_new_meta_img').val();

    $.ajax({
        url: MY_AJAX_post_new.api,
        type: 'POST',
        data: {
            action: MY_AJAX_post_new.action,
            nonce: MY_AJAX_post_new.nonce,
            post_new_title: post_new_title,
            post_new_content: post_new_content,
            post_new_meta_img: post_new_meta_img,
        }
    })
    // 成功したとき
    .done(function( response_post_new ) {
        var $articleOuter_post_new = post_new_area;
        var $response_post_new = response_post_new;
        $articleOuter_post_new.html('');
        $articleOuter_post_new.html( $response_post_new );
    })
    // 失敗したとき
    .fail(function( response_post_new ) {
        alert('失敗しました。');
    }); 

});

試したこと

上述のソースコードではできず、冒頭に書いたように「Ajaxの中にAjax」という方法を考えました。それがこちらの《変更➀》と《変更➁》です。

《変更➀》

        // 出力
        include locate_template( 'template-parts/single.php' );

↓次のように変更し、投稿されたslugを返すようにしました。

        // 出力
        $str = get_page($insert_id);
        echo $str -> post_name;    


《変更➁》

    // 成功したとき
    .done(function( response_post_new ) {
        var $articleOuter_post_new = post_new_area;
        var $response_post_new = response_post_new;
        $articleOuter_post_new.html('');
        $articleOuter_post_new.html( $response_post_new );
    })

↓次のように変更し、投稿されたslugからその記事にアクセスするようにしました。これが「Ajaxの中にAjax」という処理です。これは適切な方法ですか?

    // 成功したとき
    .done(function( response_post_new ) {
        $.ajax({
            type: 'GET',
            url: 'http://example.com/post/'+response_post_new,
            dataType: 'html'
        })
        .done(function(data) {
            var contentItems = $(data).find('.container');
            $('.container').html(contentItems);            
        })
        .fail(function () {
            alert('失敗しました。');
        });
    })


こちらの「Ajaxの中にAjax」という方法でも、投稿後にその内容を表示できたことはできたのですが、、不安が残ります。

他にもおかしな点がございましたらご指摘頂けますと幸いです。(nonceのチェック方法や変数名など、とにかく独学で不安です。)

質問は以上です。

改めまして、どうぞ宜しくお願い致します。

補足情報(FW/ツールのバージョンなど)

使っているものは全て最新です。

Wordpress → 5.0.3 
PHP → 7.3.2

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • kei344

    2019/02/12 11:24

    single.phpの内容によります。

    キャンセル

  • chacky

    2019/02/12 14:31

    といいますと、逆にどんな内容だといけませんか?
    single.php は <?php the title();> のような普通の関数を使っているだけの内容ですが、この場合だといかがですか?Ajaxは2回やるべきではないでしょうか?

    キャンセル

回答 4

+3

とりあえず locate_template は引数で include をする設定があるのでやるならそっちで。
というかget_template_partで取得しましょう。

【locate_template – WordPress私的マニュアル】
https://elearn.jp/wpman/function/locate_template.html

【Wordpressでテンプレートファイルをロードする5つの方法とその違い - Qiita】
https://qiita.com/ironsand/items/7fce685abdbf18a98c71


で、single.phpは「single.phpを表示するときに既に実行されているはずの物」が実行されていなければ表示されません。

single.php は <?php the title();> のような普通の関数を使っているだけの内容ですが、この場合だといかがですか?

WP_Queryが実行されていて、グローバル変数$GLOBALS['post']に値が入っていなければ表示されません。$insert_idに入った値をどうにかして呼び出さないと表示されません。(setup_postdata($post);するとか)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/12 15:31 編集

    ありがとうございます。仰る通り get_template_part を使います。

    そして確認事項として挙げて頂いたこちらですが、

    ・WP_Queryが実行されているかどうか
    ・グローバル変数$GLOBALS['post']に値が入っているかどうか

    これらの確認方法と、これらがないときの対処方法としてはどうすべきでしょうか?(おそらく「setup_postdataを使え」が対処方法としてのアドバイスだと思うのですが、使いどころなどが理解できませんでした。 get_template_part の手前で使えばいいのかと思ったのですがそうではないようでしたし。)

    キャンセル

  • 2019/02/12 20:43

    https://developer.wordpress.org/reference/functions/query_posts/
    ↑これ。

    キャンセル

+2

「Ajaxの中にAjax」という方法を考えたのですが、これは適切な方法ですか?

コードきっちり見たわけではないですけど、「Ajaxで得た情報を使って次のAjaxで処理を行う」のはないわけではないです。
やりようによっては1回で済ませられるように考えた方がいいかな・・・くらいですね。

「最終的にどのような結果を返したいか」というところから考えると良いです。
もしかしたら重ねなくても1発で済ませられるかもしれませんし。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/12 14:39

    まぁおかしくはないんですね。ありがとうございます。

    最終的な結果は投稿の内容の表示ですね。そんなに難しいものでもなさそうで、1発でできそうな感じがします。というか質問の「該当のソースコード」の方(1発でできると思って書いたんですが)で、なぜでできないのか理由も良く分かりません。

    キャンセル

  • 2019/02/12 15:11 編集

    「正しいかどうか」でいうと「想定通りに動かせているなら正しい」となります。
    それが効率的か、適切か、現在主流の組み方に乗っているかは別の話です。今回は「正しいかどうか」という質問なので「動いてるなら問題ないのでは?強いてなら1発でできるように考慮した方がいいけど」くらいのものです。
    きちんと想定したデータが取れているかどうかはJavaScript側でconsole.log()して確認されたほうがいいですね。

    キャンセル

  • 2019/02/12 15:37 編集

    なるほど、console.log() してみたところ、大丈夫なようでした。どうもありがとうございます。
    ひとまずAjaxを2回行う方法については問題なさそうで一安心です。
    あとは1発でできそうな方法をkei344様やmiyabi-sun様がアドバイスして下さったので、そちらの方でもう少し調べてみたいと思います。

    キャンセル

  • 2019/02/12 15:40

    そうですね。そこは回答の後半に書いた「最終的にどのような結果を返したいか」から考えて調整してください。

    キャンセル

  • 2019/02/12 15:42

    ありがとうございます。頑張ってみます。

    キャンセル

+2

「Ajaxの中にAjax」は正しい処理ですか?

質問文を最後まで読めば何となく意味はわかりますが、
要するにAjax1で不足しているデータがあるから、続けてAjax2を発射したいと言ってるわけですね。

問題の本質はJavaScript名物の非同期処理のネストだと思うので
「Ajaxの中にAjax」だとちょっともやっとしますね。
コールバック関数の入れ子による「コールバック地獄」ですね。


さて、今回の質問は「これで動いているが、良い実装なのか悪い実装なのかわからん」といったところでしょうか。
動けばなんでもええねんと言ってる輩と比べれば好ましい思想です。

Aの結果を使ってBの結果を取得しにいくためには、
上の関数スコープで仮引数や変数を定義して、
その中で作った関数をコールバック関数として利用する設計にするのはよくある手口で、
決して悪くはない、普通といった感じです。

処理が増えると延々とそこの関数内でネストしていくことになるので、
ゆくゆくを考えると「コールバック地獄」に関する理解や知識、プログラミングテクニックが必要になってくるでしょう。

コードをネストせず同じラインで一撃で書くなら下記の記事はかなり良かったです。
(ただし、超難解であることと、Promise特有の値を持ち込む辺りをうまく書くには色々とリンク先からたどって勉強する必要があるでしょう。)
複数のAjaxタスクをシーケンシャルに実行するには?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/12 15:45

    高ランキングの方々にご指導頂き大変恐縮しております。ありがとうございます。
    そうおっしゃって頂けますと少し安心できます。
    改善方法についても具体的な参考ページをどうもありがとうございます。少し難しそうですが、お蔭さまであと一時間くらい粘ってみたいと思えました。

    キャンセル

+1

Ajaxで得た情報を使って次のAjaxで処理を行う場合は遅延処理が必要です。要はAjaxを入れ子にすると
通常のPHPのように変数を受け渡しで処理してくれませんので、受け取るまで実行を手動で遅らせらないと
空っぽのデータで処理を始めることになったりと、想定外のバグに遭遇します。

はじめてajaxを使うときに知りたかったこと https://qiita.com/nekoneko-wanwan/items/bedc0e826c0842ca0b11
Ajaxが順序通り実行できない https://teratail.com/questions/128352

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/12 14:37

    必要な情報は投稿の内容です。

    投稿についてのdoneの中に2回目のAjaxを書いてそこで投稿の内容を取得しているのですけど、遅延は必要でしょうか?

    内容の取得では、リンク先にあるような「ajax()で返ってきたデータをそのまま使いたい」(https://qiita.com/nekoneko-wanwan/items/bedc0e826c0842ca0b11#ajax%E3%81%A7%E8%BF%94%E3%81%A3%E3%81%A6%E3%81%8D%E3%81%9F%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E4%BD%BF%E3%81%84%E3%81%9F%E3%81%84)をやっているつもりなのですが、いかがでしょうか。

    というのは、 done(function( response_post_new ) の response_post_new の部分です。

    キャンセル

  • 2019/02/12 14:48 編集

    自分もその記事を読み返してテスト環境で試してみたのですが、$.Ajaxだと自動で遅延処理を行ってくれるみたいですね。なので、既に遅延処理はされている状態です。

    試しに、$.postや$.getに書き換えるとレスポンスを受け取る前に、次のAjaxを実行してしまうはずです(自分の業務でそのバグやらかしてました…)。

    キャンセル

  • 2019/02/12 15:33

    そうでしたか。ではAjaxを2回やるという方法については、特に心配はなさそうですね。
    参考になる情報ばかりでした。ありがとうございます。

    キャンセル

同じタグがついた質問を見る

  • PHP

    22456questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • JavaScript

    18718questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • WordPress

    8220questions

    WordPressは、PHPで開発されているオープンソースのブログソフトウェアです。データベース管理システムにはMySQLを用いています。フリーのブログソフトウェアの中では最も人気が高く、PHPとHTMLを使って簡単にテンプレートをカスタマイズすることができます。

  • jQuery

    7519questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

  • Ajax

    1225questions

    Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。