web-dev-qa-db-ja.com

カスタムXMLRPCメソッドとユーザー認証とWooCommerce注文の認証

私は構築しているプラ​​グインのためにいくつかの情報を取得するためにカスタムXML-RPCメソッドを使っています。有効化されたとき、私のWPサイトでプラグインを購入するときに与えられたユーザー/パスワードをそこに入力することによってユーザーは自分自身を認証しなければなりません。

プラグインはこのコードを使用します。

if ( isset( $_POST['username'] ) && isset( $_POST['password'] ) ) {

        /* check against remote server */
        require_once( ABSPATH . WPINC . '/class-IXR.php' );
        $this->client = new IXR_Client( trailingslashit( CUSTOMLOGIN_UPDATE_API ) . 'xmlrpc.php' ); //*/

        $url = ( ( is_multisite() ) ? network_site_url() : site_url() );

        $client_request_args = array(
            'username'  => $_POST['username'],
            'password'  => $_POST['password'],
            'plugin'    => CUSTOMLOGINPRO_BASENAME,
            'url'       => $url
        );

        if ( !$this->client->query( 'thefrosty.is_user_authorized', $client_request_args ) ) {
            add_action( 'admin_notices', array( $this, 'error_notice' ) );
            return false;
        }

        $this->settings = get_option( CUSTOMLOGINPRO . '_settings', array() );
        $this->settings['api-key'] = $this->client->getResponse();
        update_option( CUSTOMLOGINPRO . '_settings', $this->settings );
        header( 'Location: ' . admin_url( 'options-general.php?page=' . CUSTOMLOGINPRO ) );
        die();

    } 

このフォームは、ローカルで作業しているときに200エラーが発生しますが、同じエラーコードを送信するがHostから応答を送信している(まだ心配はしていません)、ちょっと動いたように見えます。

私が行き詰まっているのはバックエンドコードです。 WPインストールのコアプラグインでクラスを作成しました。私はこれが必要なところだと思っています。フォルトコードとエラーメッセージの応答がありませんが、それらの実行方法がわかりません。ちょっと探しているだけ正しい方向に押してください..

ご覧のとおり、私はWooCommerceの注文に対してもユーザーをテストしていますが(WCからのコードで、問題ないはずです)、注文メタメタを更新しようとすると、ユーザーURLを保存するための修正が必要になるかもしれません。

class frosty_core {

function __construct() {
    add_filter( 'xmlrpc_methods', array( $this, 'xmlrpc_methods' ) );
}

/**
 * Create our custom XML-rpc method.
 * @ref http://kovshenin.com/2010/04/custom-xml-rpc-methods-in-wordpress-2151/
 */
function xmlrpc_methods( $methods ) {
    $methods['thefrosty.is_user_authorized'] = array( $this, 'thefrosty_plugin_callback' );
    return $methods;
}

/**
 * XML-prc mothod
 */
function thefrosty_plugin_callback( $args ) {

    // Parse the arguments, assuming they're in the correct order
    $username       = $args[0];
    $password       = $args[1];
    $plugin_name    = $args[2];
    $url            = $args[3];

    global $wp_xmlrpc_server;

    // Let's run a check to see if credentials are okay
    if ( !$user = $wp_xmlrpc_server->login($username, $password) ) {
        return $wp_xmlrpc_server->error;
    }

    if ( !class_exists( 'woocommerce' ) ) return 'error, please try again later';

    /* Get the user ID by name */
    $current_user_id = get_userdatabylogin( $username );

    /* woocommerce/shortcodes/shortcode-my_account.php */
    $args = array(
        'numberposts'     => -1,
        'meta_key'        => '_customer_user',
        'meta_value'      => $current_user_id,
        'post_type'       => 'shop_order',
        'post_status'     => 'publish' 
    );
    $customer_orders = get_posts( $args );      
    $match = false;

    foreach ( $customer_orders as $customer_order ) :
        $order = &new woocommerce_order();
        $order->populate( $customer_order );

        $status = get_term_by( 'slug', $order->status, 'shop_order_status' );
        if ( 'completed' !== $status->name ) return; //error, order not completed //*/

        if ( $plugin_name !== $order->items->name ) return; // you have not purchased this plugin //*/

        $match  = true;
        $apikey = $order->order_key;
    endforeach;

    if ( isset( $match ) && $match ) {
        /* woocommerce/admin/writepanels/writepanel-order_data.php */
        add_filter( 'update_order_item', create_function( '$order_items', '
            $new_meta   = &new order_item_meta();
            $meta_name  = "active_urls";
            $meta_value = esc_url( $url );

            $new_meta->add( $meta_name, $meta_value );
            return $order_items["item_meta"] => $new_meta->meta;' ) );

        return $apikey;
    }
    else return false;
}

}

5
Austin Passy

私はTwitterであなたにそれを送った、しかしここでそれはまたある。

この小さなクラスを作成して、XML-RPCをより速く実行できるようにしました。

abstract class MZAXMLRPC {
    protected $calls = Array();
    protected $namespace = "myxmlrpc";

    function __construct($namespace){
        $this->namespace = $namespace;
        $reflector = new ReflectionClass($this);
        foreach ( $reflector->getMethods(ReflectionMethod::IS_PUBLIC) as $method){
            if ($method->isUserDefined() && $method->getDeclaringClass()->name != get_class()){
                $this->calls[] = $method->name;
            }
        }
        add_filter('xmlrpc_methods', array($this, 'xmlrpc_methods'));
    }

    public function xmlrpc_methods($methods)
    {
        foreach ($this->calls as $call){
            $methods[$this->namespace . "." . $call] = array($this, "dispatch");
        }
        return $methods;
    }

    public function dispatch($args){
        global $wp_xmlrpc_server;

        $username   = $args[1];
        $password   = $args[2];
        $data = $args[3];

        if ( !$wp_xmlrpc_server->login($username, $password) )
            return $wp_xmlrpc_server->error;

        $call = $this->get_called_method();

        if (method_exists($this, $call)){
            $status = call_user_func_array(array($this, $call), array($data));
            return $status;
        }else{
            return "Method not allowed";
        }

    }

    private function get_called_method(){
        global $wp_xmlrpc_server;
        $call = $wp_xmlrpc_server->message->methodName;
        $pieces = explode(".", $call);
        return $pieces[1];
    }

}

これは抽象クラスです。あなたはそれからオブジェクトをインスタンス化することはありません。 MZAXMLRPCを継承した新しいクラスを作成し、そこに公開したいXML-RPC呼び出しごとにパブリックメソッドを作成します。

コンストラクターはReflectionを使用して、それを継承している子クラスのユーザー定義のパブリックメソッドをすべて見つけます。それからWordPressにこのメソッドのXML-RPC呼び出しを受け付けていることを伝えます。 XML-RPCメソッドは、$ namespace。$ public_method_nameという名前で公開されています。

それらの新しいXML-RPCはすべて同じメソッドdispatchに到達します。このメソッドは、最初にユーザーを検証し、リモート呼び出しを渡します。その後、XML-RPC呼び出しを処理するために宣言されたメソッドが事実上あることを確認します。すべての検証で問題なければ、子クラスの適切なメソッドへの呼び出しをディスパッチし、XML-RPCサーバーを経由してきたすべてのデータを渡します。

もう十分なちんぷんかんぷん!あなたがする必要がある唯一のことは:

class MY_XMLRPC extends MZAXMLRPC{

    public function QuoteUpload($data){

        if (!isset($data["author"]))
            return "Missing 'author' parameter";

        if (!isset($data["quote"]))
            return "Missing 'quote' parameter";

        $author = $data["author"];
        $quote = $data["quote"];

        $new_post = array(
            'post_status' => 'publish',
            'post_type' => 'mzaquotes',
            'post_title' => $quote
        );

        $new_post_id = wp_insert_post($new_post);
        wp_set_post_terms( $new_post_id, $author, 'quote_author' );

        return "OK";
    }
}

new MY_XMLRPC('my_function');

この小さなコードでは、my_function.QuoteUploadというXML-RPCメソッドを公開します。親クラスはあなたのために認証とWordPress APIを扱います。

1
MZAweb

コードに問題があるようには見えません。あなたは間違いなくXMLRPCエンドポイントを正しく追加しています。私が見る唯一の問題はこのコードに関するものです:

 if ( isset( $match ) && $match ) {
    /* woocommerce/admin/writepanels/writepanel-order_data.php */
    add_filter( 'update_order_item', create_function( '$order_items', '
        $new_meta   = &new order_item_meta();
        $meta_name  = "active_urls";
        $meta_value = esc_url( $url );

        $new_meta->add( $meta_name, $meta_value );
        return $order_items["item_meta"] => $new_meta->meta;' ) );

    return $apikey;
}

それは私がWooCommerceを十分に知らないということかもしれません...しかし、あなたはここでフィルタを追加するのではなく、ある種の関数を呼び出すべきです。あなたのコードはフィルタがヒットした場合にのみ適用されます...そして典型的なXMLRPCリクエストでは、そうではありません。

0
EAMann