Cum să utilizezi o clasă de plugin în interiorul unui template WordPress

7 mar. 2012, 09:28:07
Vizualizări: 16.9K
Voturi: 10

Scriu un plugin pentru trimiterea unei invitații către un prieten care deschide un formular când se face click pe un link. Am încapsulat toate funcțiile într-o clasă urmând codul din pluginul Report Broken Video de la @toscho. Codul relevant este mai jos:

/*
Plugin Name: Trimite Invitație  
Plugin URI: http://w3boutique.net
Descriere: Trimite prin email linkul paginii curente unui prieten
Autor: Nandakumar Chandrasekhar
Versiune: 0.1
Author URI: http://w3boutique.net/about-nanda.html
Licență: GPL2
*/

// include() sau require() orice fișiere necesare aici

// Setări și detalii de configurare merg aici
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 = 'Trimite Invitația necesită versiunea '
    . SEND_INVITATION_MIN_WORDPRESS_VERSION
    . 'sau mai nouă <a href="http://codex.wordpress.org/Upgrading_WordPress">Te rog
actualizează!</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() {
       // Pornim bufferul de output, previne afișarea directă a conținutului
       // în script, în schimb este stocat într-un buffer care poate fi golit
       // pentru a permite includerea fișierului într-o variabilă
       // Vezi 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 = 'Invitație la SwanLotus';
            $message = 'Navanitachora te invită să vizitezi acest link';
            wp_mail($to, $subject, $message);
            $result = 'Emailul a fost trimis cu succes';
    }
    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);
}
}
/* Sfârșitul fișierului */
?>

Nu știu cum să folosesc această clasă în template-ul meu pentru a afișa formularul. Știu că trebuie să instantiez clasa dar nu sunt sigur unde să pun codul și cum să accesez obiectul pentru a-l folosi în template. Am cunoștințe de OOP dar nu le-am folosit în acest context până acum și am nevoie de câteva indicații pas cu pas.

Mulțumesc mult.

0
Toate răspunsurile la întrebare 1
14

Cea mai bună metodă de a utiliza clasa ta fără a cunoaște obiectul este prin intermediul unei acțiuni. Înregistrezi acțiunea înainte ca fișierele temei pentru prezentare să fie încărcate, iar WordPress se va ocupa de restul.

Cod exemplu:

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

class Plugin_Action_Demo
{
    /**
     * Creează o nouă instanță.
     *
     * @wp-hook init
     * @see    __construct()
     * @return void
     */
    public static function init()
    {
        new self;
    }

    /**
     * Înregistrează acțiunea. Poate face și alte lucruri magice.
     */
    public function __construct()
    {
        add_action( 'plugin_action_demo', array ( $this, 'print_foo' ), 10, 1 );
    }

    /**
     * Afișează 'foo' de mai multe $times ori.
     *
     * Utilizare:
     *    <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 );
    }
}

Acum poți apela do_action( 'plugin_action_demo', 50 ); undeva în tema ta sau într-un alt plugin, și nu mai trebuie să te preocupi de funcționalitățile interne ale clasei.

Dacă dezactivezi pluginul, totul este în siguranță: WordPress pur și simplu ignoră acțiunile necunoscute, iar do_action() nu va crea probleme. În plus, alte pluginuri pot elimina sau înlocui acțiunea, astfel că ai creat o mini-API simplă cu un singur add_action().

Ai putea de asemenea să construiești un singleton:

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

    /**
     * Creează o nouă instanță dacă nu există una.
     *
     * @wp-hook init
     * @return object
     */
    public static function get_instance()
    {

        NULL === self::$instance and self::$instance = new self;
        return self::$instance;
    }

    /**
     * Nu este accesibil din exterior.
     */
    protected function __construct() {}

    /**
     * Afișează 'foo' de mai multe $times ori.
     *
     * @param int $times
     * @return void
     */
    public function print_foo( $times = 1 )
    {
        echo str_repeat( ' foo ', (int) $times );
    }
}

Acum print_foo() este accesibil prin:

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

Nu recomand modelul Singleton. Acesta are câteva dezavantaje serioase.

7 mar. 2012 09:52:51
Comentarii

Din curiozitate, care este scopul lui plugin_action_demo în add_action()? Cum știe do_action( 'print_foo', 50 ); că acțiunea este plugin_action_demo sau acel nume este irelevant?

Jared Jared
7 mar. 2012 10:05:49

Ok, am fost puțin confuz. :) Mulțumesc pentru lămurire.

Jared Jared
7 mar. 2012 10:26:57

Pentru clarificare: declare() necesită PHP 5.3+ :)

kaiser kaiser
7 mar. 2012 11:23:38

Mulțumesc, funcționează, trebuie doar să adaug niște validări și ar trebui să fiu gata. Mulțumesc @toscho, m-ai învățat multe. :-)

nandac nandac
8 mar. 2012 09:12:15

@tosco Am găsit răspunsul tău în timp ce căutam articole despre singleton pentru plugin-uri WordPress. Îți dai seama că folosești un Singleton în răspunsul tău recomandat, doar că nu îl impui? Imaginează-ți că un temar apelează new Plugin_Action_Demo?? Oricine folosește do_action('plugin_action_demo') ar declanșa două (2) apeluri la Plugin_Action_Demo->print_foo(), nu ceea ce vrei. Controversele în jurul singleton-ilor ignoră faptul că există cazuri de utilizare adecvate. Ca o informație, atât @ericmann cât și eu bloguim acum pentru a promova singleton-i pentru namespace-uri în plugin-urile WordPress, el la eamann.com și eu la hardcorewp.com.

MikeSchinkel MikeSchinkel
9 ian. 2013 16:34:53

@MikeSchinkel Abordarea pe care o recomand în prezent este aceasta: https://gist.github.com/3804204 – poți să o accesezi ca pe un Singleton, dar nu e obligatoriu.

fuxia fuxia
9 ian. 2013 16:38:04

@tocho Bine, văd că nu trebuie să accesezi exemplul tău ca un singleton, dar care e scopul? În ce cazuri de utilizare ai vrea să faci asta?

MikeSchinkel MikeSchinkel
9 ian. 2013 17:34:31

@MikeSchinkel Teste unitare și clase derivate. Și nu, nu modific vizibilitatea într-o clasă derivată decât dacă sunt obligat. :)

fuxia fuxia
9 ian. 2013 17:44:37

@toscho Testezi efectiv unitar clasele folosite ca bază pentru plugin-urile tale? Dacă da, cum te descurci cu hook-urile care nu pot fi testate fără încărcarea unei pagini? Nu face asta testarea unitară a acelor clase inutilă? Și eu folosesc moștenire pe singleton-urile mele fără probleme, de fapt e esențial în arhitectura mea; cum reprezintă o problemă? Apropo, sunt pe cale să public un post care susține singleton-urile și voi scrie o continuare despre testarea unitară. Dar dacă ai motive valide împotriva, aș vrea să le știu înainte de publicare. Mulțumesc anticipat.

MikeSchinkel MikeSchinkel
9 ian. 2013 17:51:00

@MikeSchinkel Eu folosesc http://core.trac.wordpress.org/browser/tests – timpul de încărcare al paginii nu este o problemă. Și nu-mi place ideea lui Eric de a testa o subclasă care nu este codul de producție real și care diferă în comportament. Ar trebui să scriu un articol despre asta, comentariile nu sunt făcute pentru așa ceva. :)

fuxia fuxia
9 ian. 2013 18:09:08

@toscho - Aștept cu interes articolul tău. Apropo, nu am înțeles ce ai vrut să spui prin "Nu schimb vizibilitatea într-o clasă copil decât dacă sunt nevoit."

MikeSchinkel MikeSchinkel
9 ian. 2013 20:32:29

@MikeSchinkel Vizibilitatea constructorului conform recomandării lui Eric.

fuxia fuxia
9 ian. 2013 20:33:23

@toscho Ah, Eric nu sunt eu. :)

MikeSchinkel MikeSchinkel
9 ian. 2013 20:34:03

@toscho De asemenea, când ai spus "încărcarea paginii nu este o problemă" cred că ai înțeles greșit; eu spuneam că încărcarea paginii este practic singura modalitate de a testa o clasă folosită pentru a conecta handler-ele de hook-uri cu metode, adică testarea unitară clasică nu are sens.

MikeSchinkel MikeSchinkel
9 ian. 2013 20:36:26
Arată celelalte 9 comentarii