问题描述
我已经看过关于让 WordPress 为后续的 Ajax 请求重新生成一个独特的随机数的讨论,但是对于我来说,我实际上不能让 Wordpress 做到这一点 – 每当我要求我认为应该是一个新的随机,我从 Wordpress 得到相同的随机数。我理解了 WP 的 nonce_life 的概念,甚至把它设置为别的东西,但这并没有帮助我。
我不通过本地化在标题中的 JS 对象中生成随机数 – 我在我的显示页面上进行。我可以让我的页面处理 Ajax 请求,但是当我在回调中请求一个 WP 的新的随机数时,我得到了相同的随机数,而且我不知道我做错了什么… 最终我想扩展它,以便页面上可以有多个项目,每个项目都有添加/删除的功能 – 所以我需要一个解决方案,允许一个页面的多个后续 Ajax 请求。
(而且我应该把所有这些功能都插入一个插件,所以 front-end “display page” 实际上是一个插件附带的功能…)
functions.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 显示功能,其中包括:
$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="'%20.%20$link%20.%20'">My Link</a>';
在这一点上,我会非常感谢任何线索或指针,让 WP 重新生成一个独特的随机数,每个新的 Ajax 请求…
更新:我已经解决了我的问题。上面的代码片段是有效的,但是我更改了 PHP 回调中的 $ newNonce 创建,以附加一个微秒字符串,以确保它在后续 Ajax 请求中是唯一的。
最佳解决方案
这是我自己的问题的一个非常冗长的答案,这不仅仅是解决为后续 Ajax 请求生成唯一的随机数的问题。这是一个 「添加到收藏夹」 功能,这是为了答案的目的而成为通用的 (我的功能允许用户将照片附件的帖子 ID 添加到收藏夹列表中,但这可能适用于依赖于阿贾克斯) 。我将其编码为一个独立的插件,并且有几个项目缺失 – 但是如果要复制该功能,这应该是足够的细节来提供要点。它可以在一个单独的帖子/页面上工作,但它也可以在帖子列表中工作 (例如,您可以通过 Ajax 在线添加/删除项目到收藏夹,每个帖子每个 Ajax 请求都会有自己独特的随机数) 。请记住,可能有更高效和/或更优雅的方式来执行此操作,目前这对 AJAX 有效 – 我还没有打算处理 non-Ajax $ _POST 数据。
scripts.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
});
功能 (front-end 显示和 Ajax 动作)
要输出添加/删除收藏夹链接,只需通过以下方式在您的页面/帖子中调用它:
if (function_exists('myFavoritesLink') {
myFavoritesLink($user_ID, $post->ID);
}
Front-end 显示功能:
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');
次佳解决方案
我真的不得不质疑每个 ajax 请求获得新的随机数的原因。原始的随机数将过期,但它可以使用不止一次,直到它。让 javascript 通过 ajax 收到它的目的,特别是提供一个错误的情况。 (在时间范围内,随机数的目的是将操作与用户相关联的一点安全性) 。
我不应该提到其他答案,但我是新的,不能评论上面,所以关于发布的”solution”,你每次都得到一个新的随机数,但不是在请求中使用它。每次获得微秒相同的每一个新的随机数创建的这一点肯定会很棘手。 PHP 代码正在针对原始的随机数进行验证,而 JavaScript 正在提供原始的随机数,所以它的工作原理 (因为它还没有过期) 。
参考文献
注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。