Як отримати унікальне поняття для кожного запиту Ajax?


11

Я бачив пару дискусій щодо отримання Wordpress для відновлення унікального сенсу для подальших запитів Ajax, але за все життя я не можу насправді зробити так, щоб Wordpress це робив - кожен раз, коли я запитую те, що, на мою думку, має бути новим отже, я повертаю те ж саме з Wordpress. Я розумію концепцію nonce_life WP і навіть налаштовую її на щось інше, але це мені не допомогло.

Я не генерую поняття в об'єкті JS в заголовку за допомогою локалізації - я це роблю на своїй сторінці відображення. Я можу змусити свою сторінку обробити запит Ajax, але коли я запитую нове повідомлення від WP у зворотному дзвінку, я повертаю те саме, що я не знаю, що я роблю не так ... Зрештою, я хочу розширте це, щоб на сторінці могло бути кілька елементів, кожен з яких має можливість додавання / видалення-- тому мені потрібно рішення, яке дозволить декілька наступних запитів Ajax з однієї сторінки.

(І я повинен сказати, що я помістив всю цю функціональність у плагін, тому "відображувана сторінка" на передній частині - це фактично функція, що входить до плагіна ...)

Функції.php: локалізуйте, але я тут не створюю ніякого значення

wp_localize_script('myjs', 'ajaxVars', array('ajaxurl' => 'admin-ajax.php')));

Виклик JS:

$("#myelement").click(function(e) {
    e.preventDefault();
    post_id = $(this).data("data-post-id");
    user_id = $(this).data("data-user-id");
    nonce = $(this).data("data-nonce");
    $.ajax({
      type: "POST",
      dataType: "json",
      url: ajaxVars.ajaxurl,
      data: {
         action: "myfaves",
         post_id: post_id,
         user_id: user_id,
         nonce: nonce
      },
      success: function(response) {
         if(response.type == "success") {
            nonce = response.newNonce;
            ... other stuff
         }
      }
  });
});

Отримання PHP:

function myFaves() {
   $ajaxNonce = 'myplugin_myaction_nonce_' . $postID;
   if (!wp_verify_nonce($_POST['nonce'], $ajaxNonce))
      exit('Sorry!');

   // Get various POST vars and do some other stuff...

   // Prep JSON response & generate new, unique nonce
   $newNonce = wp_create_nonce('myplugin_myaction_nonce_' . $postID . '_' 
       . str_replace('.', '', gettimeofday(true)));
   $response['newNonce'] = $newNonce;

   // Also let the page process itself if there is no JS/Ajax capability
   } else {
      header("Location: " . $_SERVER["HTTP_REFERER"];
   }
   die();
}

Функція відображення PHP Frontend, серед якої:

$nonce = wp_create_nonce('myplugin_myaction_nonce_' . $post->ID);
$link = admin_url('admin-ajax.php?action=myfaves&post_id=' . $post->ID
   . '&user_id=' . $user_ID
   . '&nonce=' . $nonce);

echo '<a id="myelement" data-post-id="' . $post->ID
   . '" data-user-id="' . $user_ID
   . '" data-nonce="' . $nonce
   . '" href="' . $link . '">My Link</a>';

На даний момент я був би дуже вдячний за будь-які підказки або вказівки щодо отримання WP для відновлення унікального поняття для кожного нового запиту Ajax ...


ОНОВЛЕННЯ: Я вирішив свою проблему. Вище наведені фрагменти коду є дійсними, проте я змінив створення $ newNonce у зворотному звороті PHP, щоб додати рядок мікросекунд, щоб гарантувати унікальність для наступних запитів Ajax.


З дуже короткого погляду: Ви створюєте поняття після того, як отримали його (на дисплеї)? Чому ви не створюєте його під час локального виклику?
кайзер

JQuery використовує початкове поняття з атрибута "data-nonce" у посиланні # myelement. Ідея полягає в тому, що сторінку може обробляти або Ajax, або сама. Мені здалося, що створення поняття одноразово через виклик локалізації виключить його з не-JS обробки, але я можу помилитися з цього приводу. У будь-якому випадку Wordpress дає мені те саме, що не повертається назад ...
Тім

Також: Чи не введення поняття в локальний виклик не завадить мати один об'єкт на сторінці, де кожен елемент може мати унікальне значення для запиту Ajax?
Тім

Створення поняття всередині локалізації створило б і зробило його доступним для цього одного сценарію. Але ви також можете додати необмежену кількість інших (ключових імен) значень локалізації з окремими значеннями.
кайзер

Якщо ви вирішили це, вам рекомендується опублікувати свою відповідь та позначити її "прийнятою". Це допоможе зберегти сайт організовано. Я просто псувався з вашим кодом, і пару речей для мене не працюють, тому подвійно звертайтеся з проханням, щоб ви опублікували своє рішення.
s_ha_dum

Відповіді:


6

Ось дуже тривала відповідь на моє власне питання, що виходить за рамки просто вирішення питання про створення унікальних понять для подальших запитів Ajax. Це функція "додати до вибраного", яка була зроблена загальною для цілей відповіді (моя функція дозволяє користувачам додавати ідентифікатори дописів до фотографій вкладених файлів до списку обраних, але це може застосовуватися до багатьох інших функцій, на які покладається Аякс). Я зашифрував це як окремий плагін, і не вистачає декількох елементів - але цього повинно бути достатньо детально, щоб надати суть, якщо ви хочете повторити функцію. Він буде працювати над окремою публікацією / сторінкою, але він також працюватиме у списках публікацій (наприклад, ви можете додавати / видаляти елементи до вибраних, вбудованих через Ajax, і кожна публікація матиме своє унікальне значення для кожного запиту Ajax). Майте на увазі, що там "

scriptpts.php

/**
* Enqueue front-end jQuery
*/
function enqueueFavoritesJS()
{
    // Only show Favorites Ajax JS if user is logged in
    if (is_user_logged_in()) {
        wp_enqueue_script('favorites-js', MYPLUGIN_BASE_URL . 'js/favorites.js', array('jquery'));
        wp_localize_script('favorites-js', 'ajaxVars', array('ajaxurl' => admin_url('admin-ajax.php')));
    }
}
add_action('wp_enqueue_scripts', 'enqueueFavoritesJS');

Favorites.js (Багато налагоджувальних матеріалів, які можна видалити)

$(document).ready(function()
{
    // Toggle item in Favorites
    $(".faves-link").click(function(e) {
        // Prevent self eval of requests and use Ajax instead
        e.preventDefault();
        var $this = $(this);
        console.log("Starting click event...");

        // Fetch initial variables from the page
        post_id = $this.attr("data-post-id");
        user_id = $this.attr("data-user-id");
        the_toggle = $this.attr("data-toggle");
        ajax_nonce = $this.attr("data-nonce");

        console.log("data-post-id: " + post_id);
        console.log("data-user-id: " + user_id);
        console.log("data-toggle: " + the_toggle);
        console.log("data-nonce: " + ajax_nonce);
        console.log("Starting Ajax...");

        $.ajax({
            type: "POST",
            dataType: "json",
            url: ajaxVars.ajaxurl,
            data: {
                // Send JSON back to PHP for eval
                action : "myFavorites",
                post_id: post_id,
                user_id: user_id,
                _ajax_nonce: ajax_nonce,
                the_toggle: the_toggle
            },
            beforeSend: function() {
                if (the_toggle == "y") {
                    $this.text("Removing from Favorites...");
                    console.log("Removing...");
                } else {
                    $this.text("Adding to Favorites...");
                    console.log("Adding...");
                }
            },
            success: function(response) {
                // Process JSON sent from PHP
                if(response.type == "success") {
                    console.log("Success!");
                    console.log("New nonce: " + response.newNonce);
                    console.log("New toggle: " + response.theToggle);
                    console.log("Message from PHP: " + response.message);
                    $this.text(response.message);
                    $this.attr("data-toggle", response.theToggle);
                    // Set new nonce
                    _ajax_nonce = response.newNonce;
                    console.log("_ajax_nonce is now: " + _ajax_nonce);
                } else {
                    console.log("Failed!");
                    console.log("New nonce: " + response.newNonce);
                    console.log("Message from PHP: " + response.message);
                    $this.parent().html("<p>" + response.message + "</p>");
                    _ajax_nonce = response.newNonce;
                    console.log("_ajax_nonce is now: " + _ajax_nonce);
                }
            },
            error: function(e, x, settings, exception) {
                // Generic debugging
                var errorMessage;
                var statusErrorMap = {
                    '400' : "Server understood request but request content was invalid.",
                    '401' : "Unauthorized access.",
                    '403' : "Forbidden resource can't be accessed.",
                    '500' : "Internal Server Error",
                    '503' : "Service Unavailable"
                };
                if (x.status) {
                    errorMessage = statusErrorMap[x.status];
                    if (!errorMessage) {
                        errorMessage = "Unknown Error.";
                    } else if (exception == 'parsererror') {
                        errorMessage = "Error. Parsing JSON request failed.";
                    } else if (exception == 'timeout') {
                        errorMessage = "Request timed out.";
                    } else if (exception == 'abort') {
                        errorMessage = "Request was aborted by server.";
                    } else {
                        errorMessage = "Unknown Error.";
                    }
                    $this.parent().html(errorMessage);
                    console.log("Error message is: " + errorMessage);
                } else {
                    console.log("ERROR!!");
                    console.log(e);
                }
            }
        }); // Close $.ajax
    }); // End click event
});

Функції (передній дисплей та дія Ajax)

Щоб вивести посилання Додати / видалити вибране, просто зателефонуйте на свою сторінку / допис за допомогою:

if (function_exists('myFavoritesLink') {
    myFavoritesLink($user_ID, $post->ID);
}

Функція переднього дисплея:

function myFavoritesLink($user_ID, $postID)
{
    global $user_ID;
    if (is_user_logged_in()) {
        // Set initial element toggle value & link text - udpated by callback
        $myUserMeta = get_user_meta($user_ID, 'myMetadata', true);
        if (is_array($myUserMeta['metadata']) && in_array($postID, $myUserMeta['metadata'])) {
            $toggle = "y";
            $linkText = "Remove from Favorites";
        } else {
            $toggle = "n";
            $linkText = "Add to Favorites";
        }

        // Create Ajax-only nonce for initial request only
        // New nonce returned in callback
        $ajaxNonce = wp_create_nonce('myplugin_myaction_' . $postID);
        echo '<p class="faves-action"><a class="faves-link"' 
            . ' data-post-id="' . $postID 
            . '" data-user-id="' . $user_ID  
            . '" data-toggle="' . $toggle 
            . '" data-nonce="' . $ajaxNonce 
            . '" href="#">' . $linkText . '</a></p>' . "\n";

    } else {
        // User not logged in
        echo '<p>Sign in to use the Favorites feature.</p>' . "\n";
    }

}

Функція дії Ajax:

/**
* Toggle add/remove for Favorites
*/
function toggleFavorites()
{
    if (is_user_logged_in()) {
        // Verify nonce
        $ajaxNonce = 'myplugin_myaction' . $_POST['post_id'];
        if (! wp_verify_nonce($_POST['_ajax_nonce'], $ajaxNonce)) {
            exit('Sorry!');
        }
        // Process POST vars
        if (isset($_POST['post_id']) && is_numeric($_POST['post_id'])) {
            $postID = $_POST['post_id'];
        } else {
            return;
        }
        if (isset($_POST['user_id']) && is_numeric($_POST['user_id'])) {
            $userID = $_POST['user_id'];
        } else {
            return;
        }
        if (isset($_POST['the_toggle']) && ($_POST['the_toggle'] === "y" || $_POST['the_toggle'] === "n")) {
            $toggle = $_POST['the_toggle'];
        } else {
            return;
        }

        $myUserMeta = get_user_meta($userID, 'myMetadata', true);

        // Init myUserMeta array if it doesn't exist
        if ($myUserMeta['myMetadata'] === '' || ! is_array($myUserMeta['myMetadata'])) {
            $myUserMeta['myMetadata'] = array();
        }

        // Toggle the item in the Favorites list
        if ($toggle === "y" && in_array($postID, $myUserMeta['myMetadata'])) {
            // Remove item from Favorites list
            $myUserMeta['myMetadata'] = array_flip($myUserMeta['myMetadata']);
            unset($myUserMeta['myMetadata'][$postID]);
            $myUserMeta['myMetadata'] = array_flip($myUserMeta['myMetadata']);
            $myUserMeta['myMetadata'] = array_values($myUserMeta['myMetadata']);
            $newToggle = "n";
            $message = "Add to Favorites";
        } else {
            // Add item to Favorites list
            $myUserMeta['myMetadata'][] = $postID;
            $newToggle = "y";
            $message = "Remove from Favorites";
        }

        // Prep for the response
        // Nonce for next request - unique with microtime string appended
        $newNonce = wp_create_nonce('myplugin_myaction_' . $postID . '_' 
            . str_replace('.', '', gettimeofday(true)));
        $updateUserMeta = update_user_meta($userID, 'myMetadata', $myUserMeta);

        // Response to jQuery
        if($updateUserMeta === false) {
            $response['type'] = "error";
            $response['theToggle'] = $toggle;
            $response['message'] = "Your Favorites could not be updated.";
            $response['newNonce'] = $newNonce;
        } else {
            $response['type'] = "success";
            $response['theToggle'] = $newToggle;
            $response['message'] = $message;
            $response['newNonce'] = $newNonce;
        }

        // Process with Ajax, otherwise process with self
        if (! empty($_SERVER['HTTP_X_REQUESTED_WITH']) && 
            strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
                $response = json_encode($response);
                echo $response;
        } else {
            header("Location: " . $_SERVER["HTTP_REFERER"]);
        }
        exit();
    } // End is_user_logged_in()
}
add_action('wp_ajax_myFavorites', 'toggleFavorites');

3

Мені справді доводиться ставити під сумнів міркування щодо отримання нового поняття для кожного запиту на ajax. Термін дії оригіналу не закінчиться, але його можна використовувати не раз, поки це станеться. Наявність javascript, отриманого ним через ajax, перемагає мету, особливо надаючи її у випадку помилки. (Ціль полягає в тому, що це трохи захищеність для асоціації дії з користувачем у часові рамки.)

Я не повинен згадувати інші відповіді, але я новий і не можу коментувати вище, тому що стосується опублікованого "рішення", ви отримуєте нове поняття щоразу, але не використовуєте його у запиті. Звичайно, було б складно отримувати мікросекунди однакові кожен раз, щоб відповідати кожному новому, створеному таким чином. PHP-код підтверджує оригінальність, і javascript надає оригінальний текст, тому він працює (тому що він ще не закінчився).


1
Проблема полягає в тому, що після її звикання термін дії закінчується і повертається -1 у функції ajax після кожного разу. Ця проблема, якщо ви перевіряєте частини форми в PHP і повертаєте помилки для друку. Використовувались невідомі форми, але насправді сталася помилка при валідації полів php, і коли форма знову надсилається, цього разу вона не може бути перевірена і check_ajax_refererповертає -1, що не є тим, чого ми хочемо!
Соломон Клоссон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.