英文:
Ajax PHP Class Structure WordPress data: { action : 'ds_calculators::myfunction', },
问题
自从我上次使用AJAX和WordPress以来已经有一段时间了。我以前的做法非常简单,使用在functions.php文件中创建函数的函数名,然后使用以下方式添加动作:
add_action('wp_ajax_nopriv_myfunction', 'myfunction');
add_action('wp_ajax_myfunction', 'myfunction');
现在我遇到了一些问题,因为现在我以不同的方式组织我的PHP代码,我的函数不再位于functions.php文件中,而是位于一个名为ds_calculators
的类中:
$.ajax({
type: 'POST',
url: my_ajax.ajaxurl,
data: { action: 'ds_calculators::myfunction' },
success: function (data, textStatus, XMLHttpRequest) {
// jQuery('#table_listing').html(''); // 清空一个元素
jQuery('.changer').html(data); // 将链接列表放入其中
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
if (typeof console === "undefined") {
console = {
log: function () { },
debug: function () { },
};
}
if (XMLHttpRequest.status == 404) {
console.log('元素未找到。');
} else {
console.log('错误:' + errorThrown);
}
}
});
现在我像这样添加动作:
add_action('wp_ajax_nopriv_myFunction', 'ds_calculators::myFunction');
add_action('wp_ajax_myFunction', 'ds_calculators::myFunction');
对于上述代码,我遇到了400(Bad Request)的问题。当函数位于一个类中时,如何包含函数名?这是否是我的问题,还是有其他问题?
英文:
It's been a while since I've worked with AJAX and WordPress. The way I used to do things was pretty straight forward and using the function name where the function is created within functions.php then I add action using :
add_action('wp_ajax_nopriv_myfunction', 'myfunction');
add_action('wp_ajax_myfunction', 'myfunction');
I'm drawing a blank here as now I structure my PHP code a little different and my function is no longer located in my functions.php file. It's located within a class named:
> ds_calculators
$.ajax({
type: 'POST',
url: my_ajax.ajaxurl,
data: { action : 'ds_calculators::myfunction', },
success: function(data, textStatus, XMLHttpRequest)
{
//jQuery('#table_listing').html(''); // empty an element
jQuery('.changer').html(data); // put our list of links into it
},
error: function(XMLHttpRequest, textStatus, errorThrown)
{
if (typeof console === "undefined")
{
console = {
log: function() {},
debug: function() {},
};
}
if (XMLHttpRequest.status == 404)
{
console.log('Element not found.');
}
else
{
console.log('Error: ' + errorThrown);
}
}
});
I now add action like this
add_action('wp_ajax_nopriv_myFunction', 'ds_calculators::myFunction');
add_action('wp_ajax_myFunction', 'ds_calculators::myFunction');
For the above I'm hitting a 400(Bad Request). How does one include the function name when that function is within a class? Is that my issue or is something else my issue?
答案1
得分: 3
不需要在JS端指定类引用:
$.ajax({
url: window.ajaxurl,
method: "post",
data: {
action: "myfunction",
},
})
在PHP模板中,如果你的函数在类中,你需要使用它的实例($this)来指定它。
add_action('wp_ajax_myfunction', array($this, 'myfunction'));
add_action('wp_ajax_nopriv_myfunction', array($this, 'myfunction'));
如果(myfunction)方法是静态的,那么你将使用类名 'ds_calculators::myfunction' 和作用域运算符。
add_action('wp_ajax_myfunction', 'ds_calculators::myfunction');
add_action('wp_ajax_nopriv_myfunction', 'ds_calculators::myfunction');
记住 wp_ajax_nopriv_{$action}
用于非经过身份验证的已注销用户触发非经过身份验证的Ajax操作。
英文:
You don't need to specify class reference on JS side:
$.ajax({
url: window.ajaxurl,
method: "post",
data: {
action: "myfunction",
},
})
...
In php template, if your function is in class, you need to specify it with reference to its instance ($this).
add_action( 'wp_ajax_myfunction', array($this, 'myfunction') );
add_action('wp_ajax_nopriv_myfunction', array($this, 'myfunction') );
if (myfucntion) method is static, then you'll use the scope operator with class name 'ds_calculators::myfunction'
add_action( 'wp_ajax_myfunction', 'ds_calculators::myfunction' );
add_action('wp_ajax_nopriv_myfunction', 'ds_calculators::myfunction' );
Remember wp_ajax_nopriv_{$action}
fires non-authenticated Ajax actions for logged-out users.
答案2
得分: 1
以下是您要翻译的内容:
add_action('wp_ajax_myfunction', array($this, 'myfunction'));
告诉WordPress,当发送一个请求到默认的ajax URL,带有操作设置为'myfunction'时,将它传递给引用的回调函数进行处理。要注意的唯一事项是'wp_ajax_${your_function/action_name}'必须与它在处理时调用的函数名称相同,并且所涉及的方法必须是公开的。
这里有一个很好的文章,介绍了如何在一个类中实现WordPress的ajax处理程序,以及我从中借鉴的内容。
namespace MyPlugin;
class AjaxHandler
{
/**
* AJAX类使用的操作挂钩。
*
* @var string
*/
const ACTION = 'my_plugin';
/**
* 用于验证AJAX请求的操作参数。
*
* @var string
*/
const NONCE = 'my-plugin-ajax';
/**
* 使用所有适当的WordPress挂钩注册AJAX处理程序类。
*/
public static function register()
{
$handler = new self();
add_action('wp_ajax_' . self::ACTION, array($handler, 'handle'));
add_action('wp_ajax_nopriv_' . self::ACTION, array($handler, 'handle'));
add_action('wp_loaded', array($handler, 'register_script'));
}
/**
* 处理我的插件的AJAX请求。
*/
public function handle()
{
// 确保我们收到了有效的AJAX请求
check_ajax_referer(self::NONCE);
// 站在一边!我要尝试... 科学!
die();
}
/**
* 注册我们的AJAX JavaScript。
*/
public function register_script()
{
wp_register_script('wp_ajax', plugins_url('path/to/ajax.js', __FILE__));
wp_localize_script('wp_ajax', 'wp_ajax_data', $this->get_ajax_data());
wp_enqueue_script('wp_ajax');
}
/**
* 获取WordPress需要输出的AJAX数据。
*
* @return array
*/
private function get_ajax_data()
{
return array(
'action' => self::ACTION,
'nonce' => wp_create_nonce(AjaxHandler::NONCE)
);
}
// 其他方法(get_comment、get_post_id、send_error)未翻译。
}
Ajax::register();
如果您有兴趣在使用REST API时使用/替代AJAX API,以下是一个我制作的快速类,演示了如何进行操作,并展示了在该设置中的命名空间,以及涵盖了wp-nonce的基础知识。
<?php
/**
* 演示REST API
*
* 此文件包含在我的主插件类中,使用'init'操作挂钩。然后实例化该类(即调用new RestApi()),并在构造函数中添加rest_api_init操作挂钩以注册路由。
*
* 作者:yourname
* 版本:$Id$
* 版权:yourname,2023年2月22日
* 默认包
*/
declare(strict_types=1);
namespace TESEO;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
/**
* RestApi类
*
* @package TESEO
*/
class RestApi {
/**
* 在常量中定义URL
*/
const DEMO_URL = 'teseo/v1';
/**
* RestApi构造函数。
*/
public function __construct() {
add_action('rest_api_init', array($this, 'register_routes'));
add_action('wp_footer', array($this, 'TESEO_plugin_path'));
}
/**
* 在页脚中添加插件路径常量
*/
public function TESEO_plugin_path(): void {
?>
<script>
// 用于前端ajax
var my_plugin_js_vars = {
'plugin_url': '<?php echo plugin_dir_url(__FILE__); ?>',
'ajax_url': '<?php echo \admin_url('admin-ajax.php'); ?>',
'nonce': '<?php echo \wp_create_nonce('npg_ajax_nonce'); ?>',
};
// 对于REST,您需要一个nonce
var my_plugin_rest_vars = {
'nonce': '<?php echo \wp_create_nonce('wp_rest'); ?>',
};
</script>
<?php
}
/**
* 在'rest_api_init'操作上注册REST API路由
*
* 这是大部分的'命名空间'发生的地方。默认的基本URL是'/wp-json/',命名空间是URL的第一部分。因此,在此示例中,URL将为'/wp-json/teseo/v1/',命名空间为'teseo'。版本是URL的第二部分,实际路由是URL的第三部分。
*/
public function register_routes(): void {
register_rest_route(
'teseo/v1',
'/dummy',
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'get_dummy'),
'permission_callback' => array($this, 'get_dummy_permissions_check'),
'args' => array(),
)
);
register_rest_route(
'teseo/v1',
'/dummy/validate',
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'get_dummy_validate'),
'permission_callback' => array($this, 'get_dummy_validate_permissions_check'),
'args' => array(
'id' => array(
'required' => true,
'validate_callback' => function ($param, $request, $key) {
return is_numeric($param);
},
),
'nonce' => array(
'required' => true,
'validate_callback' => function ($param, $request, $key) {
return wp_verify_nonce($param, 'wp_rest');
},
),
),
)
);
}
// 其他方法(get_dummy、get_dummy_permissions_check、get_dummy_validate、get_dummy_validate_permissions_check、validate_arbitrary_permissions_check)未翻译。
}
英文:
You don't need to worry too much about namespacing if you are using the wp_ajax hooks.
add_action( 'wp_ajax_myfunction', array($this, 'myfunction') );
Is telling wordpress that when a request is sent to the default ajax url with the action set to 'myfunction' to pass it to the referenced callback function on resolution. the only thing to watch out for is the the wp_ajax_${your_function/action_name}
must be the same as the function that it calls on resolution, and that the method in question must be public
Here Is a great writeup on how to implement the wordpress ajax handler in a class, and where I stole this from
namespace MyPlugin;
class AjaxHandler
{
/**
* Action hook used by the AJAX class.
*
* @var string
*/
const ACTION = 'my_plugin';
/**
* Action argument used by the nonce validating the AJAX request.
*
* @var string
*/
const NONCE = 'my-plugin-ajax';
/**
* Register the AJAX handler class with all the appropriate WordPress hooks.
*/
public static function register()
{
$handler = new self();
add_action('wp_ajax_' . self::ACTION, array($handler, 'handle'));
add_action('wp_ajax_nopriv_' . self::ACTION, array($handler, 'handle'));
add_action('wp_loaded', array($handler, 'register_script'));
}
/**
* Handles the AJAX request for my plugin.
*/
public function handle()
{
// Make sure we are getting a valid AJAX request
check_ajax_referer(self::NONCE);
// Stand back! I'm about to try... SCIENCE!
die();
}
/**
* Register our AJAX JavaScript.
*/
public function register_script()
{
wp_register_script('wp_ajax', plugins_url('path/to/ajax.js', __FILE__));
wp_localize_script('wp_ajax', 'wp_ajax_data', $this->get_ajax_data());
wp_enqueue_script('wp_ajax');
}
/**
* Get the AJAX data that WordPress needs to output.
*
* @return array
*/
private function get_ajax_data()
{
return array(
'action' => self::ACTION,
'nonce' => wp_create_nonce(AjaxHandler::NONCE)
);
}
/**
* Get the comment text sent by the AJAX request.
*
* @return string
*/
private function get_comment()
{
$comment = '';
if (isset($_POST['comment'])) {
$comment = filter_var($_POST['comment'], FILTER_SANITIZE_STRING);
}
return $comment;
}
/**
* Get the post ID sent by the AJAX request.
*
* @return int
*/
private function get_post_id()
{
$post_id = 0;
if (isset($_POST['post_id'])) {
$post_id = absint(filter_var($_POST['post_id'], FILTER_SANITIZE_NUMBER_INT));
}
return $post_id;
}
/**
* Sends a JSON response with the details of the given error.
*
* @param WP_Error $error
*/
private function send_error(WP_Error $error)
{
wp_send_json(array(
'code' => $error->get_error_code(),
'message' => $error->get_error_message()
));
}
}
Ajax::register();
If you are interested in using the REST API alongside/instead of the ajax api here is a quick class I made to go though how that would be done and showing namespacing in that setting, along with covering the basics of the wp-nonce
<?php
/**
* Demo Rest API
*
* This file is included in my main plugin class on the
* 'init' action hook. Then the class is instantiated
* (aka new RestApi() is called) and the constructor for
* this calss fires adding the rest_api_init action hook
* for the register_routes() method.
*
* @author yourname
* @version $Id$
* @copyright yourname, 22 February, 2023
* @package default
*/
declare(strict_types = 1);
namespace TESEO;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
/**
* Class RestApi
*
* @package TESEO
*/
class RestApi {
/**
* Define the url in a constant
*/
const DEMO_URL = 'teseo/v1';
/**
* RestApi constructor.
*/
public function __construct() {
add_action( 'rest_api_init', array( $this, 'register_routes' ) );
add_action( 'wp_footer', array( $this, 'TESEO_plugin_path' ) );
}
/**
* Add plugin path constant to the footer
*
* @return void
*/
public function TESEO_plugin_path(): void {
?>
<script>
// For use in the frontend ajax
var my_plugin_js_vars = {
'plugin_url': '<?php echo plugin_dir_url( __FILE__ ); ?>'
'ajax_url': '<?php echo \admin_url( 'admin-ajax.php' ); ?>',
'nonce': '<?php echo \wp_create_nonce( 'npg_ajax_nonce' ); ?>',
};
// For use with rest you want a nonce
var my_plugin_rest_vars = {
'nonce': '<?php echo \wp_create_nonce( 'wp_rest' ); ?>',
};
</script>
<?php
}
/**
* Register rest API routes on the 'rest_api_init' action
*
* This is where most of the 'namespacing' happens.
* The default base url is '/wp-json/' with the namespace being the first part of the url.
* So in this case the url would be '/wp-json/teseo/v1/' with the namespace being 'teseo'.
* The version is the second part of the url, and the actual route is the third part of the url.
*/
public function register_routes(): void {
register_rest_route(
'teseo/v1',
'/dummy',
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_dummy' ),
'permission_callback' => array( $this, 'get_dummy_permissions_check' ),
'args' => array(),
)
);
register_rest_route(
'teseo/v1',
'/dummy/validate',
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_dummy_validate' ),
'permission_callback' => array( $this, 'get_dummy_validate_permissions_check' ),
'args' => array(
'id' => array(
'required' => true,
'validate_callback' => function( $param, $request, $key ) {
return is_numeric( $param );
},
),
'nonce' => array(
'required' => true,
'validate_callback' => function( $param, $request, $key ) {
return wp_verify_nonce( $param, 'wp_rest' );
},
),
),
),
);
}
/**
* Get dummy
*
* @param WP_REST_Request $request Request.
*
* @return WP_REST_Response|WP_Error
*/
public function get_dummy( WP_REST_Request $request ): WP_REST_Response {
$data = array(
'message' => 'Hello World',
);
return new WP_REST_Response( $data, 200 );
}
/**
* Get dummy permissions check
*
* @param WP_REST_Request $request Request.
*
* @return bool|WP_Error
*/
public function get_dummy_permissions_check( WP_REST_Request $request ): bool {
return true;
}
/**
* Get dummy validate
*
* @param WP_REST_Request $request Request.
* @return WP_REST_Response|WP_Error
*/
public function get_dummy_validate( WP_REST_Request $request ): WP_REST_Response {
$data = array(
'message' => 'Hello World',
);
return new WP_REST_Response( $data, 200 );
}
/**
* Get dummy validate permissions check
*
* We don't actually need to do anything here, because the permission check
* is already done in the parameter validation. But if we wanted to, we could
* do extra checks here for the current user, role or whatever.
*
* @param WP_REST_Request $request Request.
* @return bool|WP_Error
*/
public function get_dummy_validate_permissions_check( WP_REST_Request $request ) {
// check if the user has the role 'administrator'
if ( ! current_user_can( 'administrator' ) ) {
return new WP_Error( 'rest_forbidden', esc_html__( 'You do not have permission to do this.', 'textdomain' ), array( 'status' => 401 ) );
}
// check if the users id is 1
if ( 1 !== get_current_user_id() ) {
return new WP_Error( 'rest_forbidden', esc_html__( 'You do not have permission to do this.', 'textdomain' ), array( 'status' => 401 ) );
}
// arbitrary check for some other condition
return $this->validate_arbitrary_permissions_check( $request ) ? true : new WP_Error( 'rest_forbidden', esc_html__( 'You do not have permission to do this.', 'textdomain' ), array( 'status' => 401 ) );
}
/**
* Validate that the user making the request has made atleast 5 posts
* in the last 30 days.
*
* @param WP_REST_Request $request Request.
* @return bool|WP_Error
*/
public function validate_arbitrary_permissions_check( WP_REST_Request $request ) {
// get the current user
$user = wp_get_current_user();
// get the users posts
$posts = get_posts(
array(
'author' => $user->ID,
'date_query' => array(
array(
'after' => '30 days ago',
),
),
'post_type' => 'post',
'post_status' => 'publish',
)
);
// check if the user has made atleast 5 posts in the last 30 days
if ( count( $posts ) < 5 ) {
return new WP_Error( 'rest_forbidden', esc_html__( 'You do not have permission to do this.', 'textdomain' ), array( 'status' => 401 ) );
}
return true;
}
}
答案3
得分: 0
你应该修复你的ajax调用,并将action参数移动到其他参数的旁边,如type, url, success,而不是放在data里面。你只是在声明动作名称,与php类层次结构无关。实际的动作名称与wp_ajax_{action}和wp_ajax_nopriv_{action}相关联。这就是为什么动作名称myFunction必须用作add_action('wp_ajax_myFunction', 'ajax_callback');。关于这个更多信息可以在这里阅读:https://developer.wordpress.org/reference/hooks/wp_ajax_action/
$.ajax({
type: 'POST',
url: my_ajax.ajaxurl,
action: 'myfunction',
data: {
field1: "pass",
field2: "some",
field3: "data"
},
success: function (data, textStatus, XMLHttpRequest) {
//jQuery('#table_listing').html(''); // empty an element
jQuery('.changer').html(data); // put our list of links into it
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
if (typeof console === "undefined") {
console = {
log: function () {},
debug: function () {},
};
}
if (XMLHttpRequest.status == 404) {
console.log('Element not found.');
} else {
console.log('Error: ' + errorThrown);
}
}
});
移动到PHP方面...
你可以以两种方式调用类对象内的方法:
- 如果它是一个普通方法,你应该创建你的类对象的实例,然后将其用作数组,例如:
class ExampleClass {
public function ajax_callback(){
// 做一些事情
// 用"wp_send_json" / "wp_send_json_success" / "wp_send_json_error" 和 die() 函数结束调用
wp_send_json("DATA");
die();
}
}
$example_class_object = new ExampleClass();
// 示例wp_ajax操作:
add_action('wp_ajax_nopriv_myFunction', [$example_class_object, 'ajax_callback']);
add_action('wp_ajax_myFunction', [$example_class_object, 'ajax_callback']);
- 如果你不想初始化一个对象,你可以将一个方法声明为静态的。这将允许你直接按名称调用方法,例如:
class StaticExmaple {
public static function ajax_callback(){
// 做一些事情
// 用"wp_send_json" / "wp_send_json_success" / "wp_send_json_error" 和 die() 函数结束调用
wp_send_json("DATA");
die();
}
}
// 示例wp_ajax操作:
add_action('wp_ajax_nopriv_myFunction', ['StaticExmaple', 'ajax_callback']);
add_action('wp_ajax_myFunction', ['StaticExmaple', 'ajax_callback']);
英文:
You should fix your ajax call and move action argument next to the others like type, url, success instead of inside data. You are just declaring te action name and it's not related to php class hierarchy. The actual action name it's connected to wp_ajax_{action} and wp_ajax_nopriv_{action}. That's the reason the action name myFunction have to be used as add_action('wp_ajax_myFunction', 'ajax_callback');. More about that you can read here: https://developer.wordpress.org/reference/hooks/wp_ajax_action/
$.ajax({
type: 'POST',
url: my_ajax.ajaxurl,
action: 'myfunction',
data: {
field1: "pass",
field2: "some",
field3: "data"
},
success: function (data, textStatus, XMLHttpRequest) {
//jQuery('#table_listing').html(''); // empty an element
jQuery('.changer').html(data); // put our list of links into it
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
if (typeof console === "undefined") {
console = {
log: function () {},
debug: function () {},
};
}
if (XMLHttpRequest.status == 404) {
console.log('Element not found.');
} else {
console.log('Error: ' + errorThrown);
}
}
});
Moving to PHP side...
You are able to call the methods inside of the class object in two ways:
- If it's a normal method, you should create an instance of your class object and then use it as the array, for example:
class ExampleClass {
public function ajax_callback(){
// Do staff
// end the call with "wp_send_json"/"wp_send_json_success"/"wp_send_json_error" and die() function
wp_send_json( "DATA" );
die();
}
}
$example_class_object = new ExampleClass();
// Example wp_ajax actions:
add_action('wp_ajax_nopriv_myFunction', [$example_class_object, 'ajax_callback']);
add_action('wp_ajax_myFunction', [$example_class_object, 'ajax_callback']);
- If you don't want to initialize an object, you can declare a method as static. That will allow you to call a method directly by name, for example:
class StaticExmaple {
public static function ajax_callback(){
// Do staff
// end the call with "wp_send_json"/"wp_send_json_success"/"wp_send_json_error" and die() function
wp_send_json( "DATA" );
die();
}
}
// Example wp_ajax actions:
add_action('wp_ajax_nopriv_myFunction', ['StaticExmaple', 'ajax_callback']);
add_action('wp_ajax_myFunction', ['StaticExmaple', 'ajax_callback']);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论