dongzhao3040
dongzhao3040
2019-04-23 15:36

如何在我的ajax-php脚本中访问wordpress函数

I'm trying to call a WordPress function ( get_avatar($id) ) from a php script that is being accessed in an ajax referenced call from an enqueued javascript file. (Saying this out load already makes my head hurt).

As a an example, I've created a plugin for WordPress: hmm-test. It is implemented in hmm-test.php. This script enqueues a javascript file: test.js. Within the js I have an xhttprequest call that POSTS to hmm-test.php, which branches on a test for a POST variable.

When hmm-test.php is called as a GET, for example using the WordPress URL for the page where the short-code is embedded, I can call WordPress functions. From the POST branch, I want to be able to call WordPress native functions as well to return that as part of the JSON payload.

So my question is: can I make the 'POST' side branch of hmm-test.php 'wordpress-aware' such that I can call native WP functions from within it?

I'm stuck - not sure what else to try. I tried creating a REST endpoint to call via an Ajax URL early on but kept running into auth problems. If this would work, I can spend time working through it, but I've found the OAuth bits tricky. I had it working for something else, and lost it. If there's a way to do it with a simple POST, that's good enough for my proof of concept.

Here is the plugin PHP script and the enqueued javascript in their entirety:

<?php
/*
Plugin Name:  HMM Test
*/

if (strlen($_POST['action'])) {

        $rv["payload"] = get_avatar(108);
        $rv["payload"] = "This is the payload message";
        $rv["status"]  = 'SUCCESS';
        echo json_encode($rv);

} else {

        function hmm_test_enqueue_scripts() {

                wp_register_script( 'test-js', plugins_url( '/js/test.js', __FILE__ ), '', '1.0', all );

        }

        add_action( 'wp_enqueue_scripts', 'hmm_test_enqueue_scripts' );

        /* ***************************************************************************
         * This is the main page
         * ************************************************************************* */

        add_shortcode( 'test-contents', 'my_test_contents' );

        function my_test_contents() {

                wp_enqueue_script( 'test-js' );

                wp_localize_script('test-js', 'wpVariables', array(
                        'pluginsUrl' => plugins_url(),
                        'pluginDir' => trailingslashit( dirname( plugin_basename( __FILE__ ) ) ),
                        'userID' => 37
                ));

                echo "Wordpress functions test: get_avatar()";
                echo get_avatar( 37 );          # -- This works from the plugin script

                echo '<button type="button" class="test-button">Click to crash</button>';
        }
}

And the JS:

(function () {
        var c = document.getElementsByClassName('test-button');

        for (var i = 0; i < c.length; i++ ) {
                c[i].addEventListener('click', doTest, false);
        }
})();

function doTest() {

        console.log("In doTest()");

        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
                if (this.readyState == 4 && this.status == 200) {
                        console.log("responseText: " + this.responseText);
                }
        };

        var ajaxUrl = wpVariables.pluginsUrl + '/' + wpVariables.pluginDir + 'hmm-test.php';
        var userid  = wpVariables.userID;

        xhttp.open("POST", ajaxUrl, true);
        xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        let arg = "action=update" + "&userid=" + userid;
console.log("Calling URL:" + ajaxUrl + " with arg: " + arg);
        xhttp.send(arg);
}

When I place the shortcode [hmm-test] in a Wordpress page, it loads fine, and I get the expected 'Wordpress functions test...', the proper avatar image for user 37 (hard-coded in this example), and a button to click to make things crash (for now!).

Clicking the button, I see this is the console window:

In doTest() test.js?ver=1.0:40 Calling URL:https://not-my-real-url.com/wp-content/plugins/hmm-test/hmm-test.php with arg: action=update&userid=37 test.js?ver=1.0:30 responseText: Fatal error: Call to undefined function get_avatar() in /home4/mifydnu/public_html/wp-content/plugins/hmm-test/hmm-test.php on line 8

Obviously, and perhaps unsurprisingly, nothing is known about the get_avatar() function. This makes sense - I'm just calling some PHP script via a URL. Makes no difference that the script is sitting in a Wordpress directory somewhere. But I am stumped at how to get around this.

Thanks for any advice!

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

2条回答

  • doumi9618 doumi9618 2年前

    Since you're sending your POST request directly to your PHP script -instead of using the AJAX API or the REST API- you're basically bypassing the entire WordPress core and so none of its functions are available to the script, hence the "Call to undefined function" error you're seeing now.

    Here's your code refactored so it uses the AJAX API instead so all WP functions are available to your script:

    Main plugin file:

    <?php
    /**
     * Plugin Name:  HMM Test
     */
    
    /**
     * Registers scripts and stylesheets.
     */
    function hmm_test_enqueue_scripts() {
        wp_register_script( 'test-js', plugins_url( '/js/test.js', __FILE__ ), array(), '1.0', true );
        wp_localize_script('test-js', 'wpVariables', array(
            'ajaxurl' => admin_url( 'admin-ajax.php' ),
            'userID' => 37
        ));
        wp_enqueue_script( 'test-js' );
    }
    add_action( 'wp_enqueue_scripts', 'hmm_test_enqueue_scripts' );
    
    /**
     * Registers the shortcode.
     */
    function my_test_contents() {
        echo "Wordpress functions test: get_avatar()";
        echo get_avatar( 37 );          # -- This works from the plugin script
    
        echo '<button type="button" class="test-button">Click to crash</button>';
    }
    add_shortcode( 'test-contents', 'my_test_contents' );
    
    /**
     * Handles the AJAX request.
     */
    function my_action() {
        $rv["payload"] = get_avatar(108);
        $rv["payload"] = "This is the payload message";
        $rv["status"]  = 'SUCCESS';
        echo json_encode($rv);
    
        wp_die(); // this is required to terminate immediately and return a proper response
    }
    add_action( 'wp_ajax_my_action', 'my_action' );
    

    test.js now becomes:

    (function () {
        var c = document.getElementsByClassName('test-button');
    
        for (var i = 0; i < c.length; i++ ) {
                c[i].addEventListener('click', doTest, false);
        }
    })();
    
    function doTest() {
    
        console.log("In doTest()");
    
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                console.log("responseText: " + this.responseText);
            }
        };
    
        var ajaxUrl = wpVariables.ajaxurl;
        var userid  = wpVariables.userID;
    
        xhttp.open("POST", ajaxUrl, true);
        xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    
        // The "action" parameter is the name of the (pardon the redundancy) "action" 
        // registered with "wp_ajax_" (see main plugin file for reference)
        //
        // You can name this whatever you want but make sure it's unique
        // to your plugin to avoid name collisions.
        let arg = "action=my_action" + "&userid=" + userid;
    
        console.log("Calling URL:" + ajaxUrl + " with arg: " + arg);
    
        xhttp.send(arg);
    
    }
    

    Important: There are no validations whatsoever (security nonces, $_POST variable checks, etc) which you should add to your code to make it more reliable/secure.

    点赞 评论 复制链接分享
  • dongzhuang6247 dongzhuang6247 2年前

    You need to use Wordpress' ajax script. It involves writing your code into functions and using WordPress hooks to get them attached to the WP ajax script. See https://codex.wordpress.org/AJAX_in_Plugins.

    A big advantage to this is that some sites have security settings in place that will disallow direct access to php files in plugins, which will break your AJAX unless you use this built-in method. I had to convert a really big plugin to use this method after our new security plugin broke it. The result was actually a lot less coding for me and a lot more stability and better performance.

    点赞 评论 复制链接分享

为你推荐