web-dev-qa-db-fra.com

méthode XMLRPC personnalisée plus authentification de la commande utilisateur et de WooCommerce

Je travaille avec une méthode XML-RPC personnalisée pour capturer des informations pour un plugin que je construis. Lorsqu'il est activé, l'utilisateur doit s'authentifier en entrant son nom d'utilisateur/mot de passe lors de l'achat du plug-in sur mon site WP.

Le plugin utilise ce code:

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();

    } 

Le formulaire est soumis et ressemble à un peu à son fonctionnement, obtenant une erreur 200 lorsqu’il travaille en local, mais testé avec un autre plugin qui envoie le même code d'erreur, mais envoie des réponses à partir de l'hôte (pas de soucis pour l'instant).

Ce sur quoi je suis coincé, c'est le code final. J'ai créé une classe dans un plug-in principal sur mon WP installation. Je suppose que c'est là où il faut. Il me manque des réponses aux codes d’erreur et aux messages d’erreur, je ne sais pas comment faire. Je cherche juste un peu Poussez dans la bonne direction ..

Comme vous pouvez le constater, je teste également l'utilisateur par rapport à une commande WooCommerce (le code de WC devrait être bon), mais essayer ensuite de mettre à jour la méta de la commande peut nécessiter des correctifs pour enregistrer les URL des utilisateurs.

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

Je vous l'ai envoyé sur Twitter, mais le voici à nouveau.

J'ai créé cette petite classe pour m'aider à faire plus rapidement 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];
    }

}

Ceci est une classe abstraite. Vous n'instancierez pas d'objets. Vous allez créer une nouvelle classe qui hérite de MZAXMLRPC et créer des méthodes publiques pour chaque appel XML-RPC que vous souhaitez exposer.

Le constructeur utilise Reflection pour rechercher toutes les méthodes publiques définies par l'utilisateur de la classe enfant qui en hérite. Ensuite, cela indiquera à WordPress que nous acceptons les appels XML-RPC pour ces méthodes. Les méthodes XML-RPC sont exposées avec le nom $ namespace. $ Public_method_name.

Tous ces nouveaux XML-RPC arriveront à la même méthode, dispatch. Cette méthode valide d'abord l'utilisateur/passe pour l'appel distant, puis vérifie qu'il existe effectivement une méthode déclarée pour prendre en charge l'appel XML-RPC. Si tout est valide, ok, l'appel sera envoyé à la méthode appropriée de la classe enfant, en transmettant toutes les données transmises par le serveur XML-RPC.

Assez de charabia déjà! La seule chose à faire est de:

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');

Ce petit morceau de code exposera une méthode XML-RPC appelée my_function.QuoteUpload. La classe parente traitera pour vous de l’authentification et des API WordPress.

1
MZAweb

Rien ne semble mal avec votre code. Vous ajoutez définitivement le point de terminaison XMLRPC correctement. Le seul problème que je vois est avec ce code:

 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;
}

Peut-être que je ne connais pas suffisamment WooCommerce ... mais vous devriez invoquer une fonction quelconque, sans ajouter de filtre. Votre code ne sera appliqué que si le filtre est touché ... et dans une requête XMLRPC typique, ce ne sera pas le cas.

0
EAMann