Utilizzare una classe plugin all'interno di un template

7 mar 2012, 09:28:07
Visualizzazioni: 16.9K
Voti: 10

Sto scrivendo un plugin per inviare un invito a un amico che apre un form quando viene cliccato un link. Ho incapsulato tutte le funzioni in una classe seguendo il codice del plugin Report Broken Video di @toscho. Il codice rilevante è il seguente:

/*
Plugin Name: Send Invitation
Plugin URI: http://w3boutique.net
Description: Invia via email il link della pagina corrente a un amico
Author: Nandakumar Chandrasekhar
Version: 0.1
Author URI: http://w3boutique.net/about-nanda.html
License: GPL2
*/

// include() o require() di eventuali file necessari qui

// Impostazioni e dettagli di configurazione vanno qui
define('SEND_INVITATION_MIN_WORDPRESS_VERSION', '3.1.1');

define('SEND_INVITATION_PLUGIN_URL', plugins_url('', __FILE__));

add_action( 'init', array( 'SendInvitation', 'nc_sendinvitation_init' ) );

class SendInvitation {

    protected $nonce_name = 'nc_sendinvitation';
    protected $post_url = '';

    public static function nc_sendinvitation_init() {
        new self;
    }

    public function __construct() {
        add_action( 'init', array(&$this, 'nc_sendinvitation_head' ));
        add_action( 'init', array(&$this,  'nc_sendinvitation_check_wordpress_version' ));
       add_action( 'init', array(&$this, 'nc_sendinvitation_form_action' ));
       //$this->post_url = $this->nc_sendinvitation_get_post_url();
   }

   public function nc_sendinvitation_head() {
       wp_enqueue_script( 'jquery' );
       wp_enqueue_script( 'send_invitation_js',
        plugins_url( 'js/send-invitation.js', __FILE__ ),
        array( 'jquery' ) );

       wp_enqueue_style( 'send_invitation_css',
        plugins_url( 'css/send-invitation.css', __FILE__ ) );
   }

   public function nc_sendinvitation_check_wordpress_version() {
       global $wp_version;

       $exit_msg = 'Send Invitation richiede la versione '
    . SEND_INVITATION_MIN_WORDPRESS_VERSION
    . 'o successiva <a href="http://codex.wordpress.org/Upgrading_WordPress">Si prega di
aggiornare!</a>';

       if ( version_compare( $wp_version, SEND_INVITATION_MIN_WORDPRESS_VERSION, '<') )
       {
            exit( $exit_msg );
       }
   }

   public function nc_sendinvitation_form_action() {

        $action = '';
        if ( $_SERVER['REQUEST_METHOD'] != 'POST' )
        {
             $action = $this->nc_sendinvitation_get_form();
        }
        else if ( $_SERVER['REQUEST_METHOD'] == 'POST' ) {
            $action = $this->nc_sendinvitation_handle_submit();
        }
        return $action;
   }

   public function nc_sendinvitation_get_form() {
       // Avvia l'output buffer, previene l'output diretto del contenuto nello
       // script, invece viene memorizzato in un buffer che può poi essere svuotato
       // per permettere al file include di essere memorizzato in una variabile
       // Vedi http://www.codingforums.com/showthread.php?t=124537
       ob_start();
       include('send-invitation-form.php');
       $send_invitation_link = ob_get_clean();

       return $send_invitation_link;
   }

   public function nc_sendinvitation_handle_submit() {
         if ( isset( $_POST['form_type'] ) && ( $_POST['form_type'] == 'nc_sendinvitation' ) ) {
            $to = 'navanitachora@gamil.com';
            $subject = 'Invito a SwanLotus';
            $message = 'Navanitachora ti invita a visualizzare questo link';
            wp_mail($to, $subject, $message);
            $result = 'Email inviata con successo';
    }
    else {
        $result = $this->nc_sendinvitation_get_form();
    }
    return $result;
}

public function nc_sendinvitation_get_post_url() {
    global $post;
    $blog_id = get_option('page_for_posts');
    $post_id = '';
    if (is_home($blog_id)) {
        $post_id = $blog_id;
    } else {
        $post_id = $post->ID;
    }

    return get_permalink($post_id);
}
}
/* Fine del File */
?>

Non so come utilizzare questa classe nel mio template per visualizzare il form. So che devo istanziare la classe ma non sono sicuro dove inserire il codice e come accedere all'oggetto per utilizzarlo nel mio template. Ho conoscenze di OOP ma non l'ho mai usato in questo contesto e avrei bisogno di una guida passo passo.

Grazie mille.

0
Tutte le risposte alla domanda 1
14

Il modo migliore per utilizzare la tua classe senza conoscere l'oggetto è un'azione. Registri l'azione prima che i file del tema per la presentazione vengano caricati, WordPress si occuperà del resto.

Codice di esempio:

<?php # -*- coding: utf-8 -*-
/**
 * Plugin Name: Plugin Action Demo
 */
add_action( 'init', array ( 'Plugin_Action_Demo', 'init' ) );

class Plugin_Action_Demo
{
    /**
     * Crea una nuova istanza.
     *
     * @wp-hook init
     * @see    __construct()
     * @return void
     */
    public static function init()
    {
        new self;
    }

    /**
     * Registra l'azione. Può fare anche altre cose magiche.
     */
    public function __construct()
    {
        add_action( 'plugin_action_demo', array ( $this, 'print_foo' ), 10, 1 );
    }

    /**
     * Stampa 'foo' multiple $times.
     *
     * Utilizzo:
     *    <code>do_action( 'plugin_action_demo', 50 );</code>
     *
     * @wp-hook plugin_action_demo
     * @param int $times
     * @return void
     */
    public function print_foo( $times = 1 )
    {
        print str_repeat( ' foo ', (int) $times );
    }
}

Ora puoi chiamare do_action( 'plugin_action_demo', 50 ); da qualche parte nel tuo tema o in un altro plugin, e non dovrai più preoccuparti del funzionamento interno della classe.

Se disattivi il plugin sei comunque al sicuro: WordPress semplicemente ignora le azioni sconosciute e il do_action() non farà alcun danno. Inoltre, altri plugin possono rimuovere o sostituire l'azione, quindi hai creato una bella mini API con un semplice add_action().

Potresti anche creare un singleton:

<?php # -*- coding: utf-8 -*-
/**
 * Plugin Name: Plugin Singleton Demo
 */
class Plugin_Singleton_Demo
{
    protected static $instance = NULL;

    /**
     * Crea una nuova istanza se non ce n'è già una.
     *
     * @wp-hook init
     * @return object
     */
    public static function get_instance()
    {
        NULL === self::$instance and self::$instance = new self;
        return self::$instance;
    }

    /**
     * Non accessibile dall'esterno.
     */
    protected function __construct() {}

    /**
     * Stampa 'foo' multiple $times.
     *
     * @param int $times
     * @return void
     */
    public function print_foo( $times = 1 )
    {
        echo str_repeat( ' foo ', (int) $times );
    }
}

Ora print_foo() è accessibile tramite:

Plugin_Singleton_Demo::get_instance()->print_foo();

Non raccomando il pattern Singleton. Ha alcuni gravi svantaggi.

7 mar 2012 09:52:51
Commenti

Per curiosità, qual è lo scopo di plugin_action_demo in add_action()? Come fa do_action( 'print_foo', 50 ); a sapere che l'azione è plugin_action_demo o quel nome è irrilevante?

Jared Jared
7 mar 2012 10:05:49

Ok, ero un po' confuso. :) Grazie per aver chiarito.

Jared Jared
7 mar 2012 10:26:57

Per completezza: declare() richiede PHP 5.3+ :)

kaiser kaiser
7 mar 2012 11:23:38

Grazie, funziona, devo solo aggiungere un po' di validazione e dovrei aver finito. Grazie @toscho mi hai insegnato molto. :-)

nandac nandac
8 mar 2012 09:12:15

@tosco Ho trovato la tua risposta cercando articoli sui singleton per i plugin di WordPress. Ti rendi conto che stai usando un Singleton nella tua risposta consigliata, semplicemente non lo stai imponendo? Immagina se un themer chiamasse new Plugin_Action_Demo?? Chiunque usasse do_action('plugin_action_demo') attiverebbe due (2) chiamate a Plugin_Action_Demo->print_foo(), non quello che vuoi. La furia contro i singleton ignora che ci siano casi d'uso appropriati. Come informazione, sia @ericmann che io stiamo scrivendo articoli per sostenere l'uso dei singleton per il namespacing dei plugin WordPress, lui su eamann.com e io su hardcorewp.com.

MikeSchinkel MikeSchinkel
9 gen 2013 16:34:53

@MikeSchinkel L'approccio che attualmente consiglio è questo: https://gist.github.com/3804204 – puoi accedervi come un Singleton, ma non sei obbligato.

fuxia fuxia
9 gen 2013 16:38:04

@tocho Va bene, vedo che non devi accedere al tuo esempio come un singleton, ma qual è il vantaggio? In quali casi d'uso vorresti farlo?

MikeSchinkel MikeSchinkel
9 gen 2013 17:34:31

@MikeSchinkel Test unitari e classi figlie. E no, non cambio la visibilità in una classe figlia a meno che non sia obbligato. :)

fuxia fuxia
9 gen 2013 17:44:37

@toscho Testi effettivamente le classi usate come base per i tuoi plugin? Se sì, come gestisci gli hook che non possono essere testati senza un caricamento di pagina? Non rende inutile il test unitario di quelle classi? E io sto facendo il subclassing dei miei singleton senza problemi, anzi è fondamentale per la mia architettura; perché dovrebbe essere un problema? A proposito, sto per pubblicare un post che promuove i singleton e scriverò un seguito riguardante il testing unitario. Ma se hai ragioni valide contrarie, vorrei saperlo prima di pubblicare. Grazie in anticipo.

MikeSchinkel MikeSchinkel
9 gen 2013 17:51:00

@MikeSchinkel Io uso http://core.trac.wordpress.org/browser/tests – il tempo di caricamento della pagina non è un problema. E non mi piace l'idea di Eric di testare una sottoclasse che non è il codice di produzione effettivo e differisce nel comportamento. Dovrei scrivere un post su questo, i commenti non sono fatti per questo. :)

fuxia fuxia
9 gen 2013 18:09:08

@toscho - Non vedo l'ora di leggere il tuo post sul blog. A proposito, non ho capito cosa intendevi con "Non cambio la visibilità in una classe figlia a meno che non sia costretto."

MikeSchinkel MikeSchinkel
9 gen 2013 20:32:29

@MikeSchinkel La visibilità del costruttore come raccomandato da Eric.

fuxia fuxia
9 gen 2013 20:33:23

@toscho Ah, Eric non sono io. :)

MikeSchinkel MikeSchinkel
9 gen 2013 20:34:03

@toscho Inoltre, quando hai detto "il caricamento della pagina non è un problema" penso tu abbia frainteso; intendevo dire che il caricamento della pagina è praticamente l'unico modo per testare una classe utilizzata per collegare i gestori di hook con i metodi, cioè che il classico unit testing non ha senso.

MikeSchinkel MikeSchinkel
9 gen 2013 20:36:26
Mostra i restanti 9 commenti