Aggiorna un plugin mantenendo la retrocompatibilità: generale
-
-
Dato che haimenzionato unpost sulla creazione diistanze senzaglobale,ecco unpost di questotipo con collegamenti amolti altripost correlati: http://hardcorewp.com/2013/using-singleton-classes-for-wordpress-plugins/Since you mentioned a post about instantiating without a global here's such a post about with links to several other related posts: http://hardcorewp.com/2013/using-singleton-classes-for-wordpress-plugins/
- 0
- 2013-04-11
- MikeSchinkel
-
1 risposta
- voti
-
- 2013-03-02
Inomi delle classinonfanno distinzionetramaiuscolee minuscolein PHP (con un'eccezione ),quindinon dovrebbeessere unproblema.
L'accesso all'istanza delpluginprincipaleper una classe èpossibile con unmetodo statico
get_instance()
(esempio ). Non devi creare un singletonper questo. Enon dovrebbeinterrompere la compatibilità con le versioniprecedenti.Se avevimetodipubblicineltuo vecchio codicee questimetodi sono stati utilizzati da codice diterzeparti,devimantenere lafirmaesatta. Quindi omantieniilmetodoe passa la chiamata all'istanza dellanuova classe,oppure - se ci sonomolti di questimetodi - usa
__call()
per catturaretutti questimetodiin uno.(Aggiorna) Datoiltuoesempio di
remove_action()
... questo è complicato. Se aggiungi ora questa richiamata da un'altra classe,nonesiste unmodo sicuroper rimanere compatibile con le versioniprecedenti,perchénonpuoi "guardare" le chiamateremove_action()
.
Potresti registrareil vecchio callbacke implementare un Observer peresserenotato se è stato rimosso .Un'idea con cui hogiocatoperprogettifuturi: separare l'APIpubblica dalla logicainterna.
Esempio: crea una classe
Plugin_API
e passatuttigli oggetti daltuo codice funzionante a quella classe quando sonoimpostati. Quando viene chiamato unmetodo da quell'API,passa la chiamata all'oggetto responsabile internamente ,senzaesporre la struttura deltuoplugin alpubblico.Codice diesempio
add_action( 'wp_loaded', array ( Plugin_Controller::get_instance(), 'plugin_setup' ) ); class Plugin_Controller { protected static $instance = NULL; public static function get_instance() { NULL === self::$instance and self::$instance = new self; return self::$instance; } public function plugin_setup() { $api = Plugin_API::get_instance(); $api->add_object( 'post_type', new Plugin_Custom_Post_Type ); $api->add_object( 'taxonomy', new Plugin_Custom_Taxonomy ); $api->add_object( 'options_page', new Plugin_Options_Page ); add_action( 'wp_head', array ( $api, 'wp_head' ) ); } } class Plugin_Custom_Post_Type {} class Plugin_Custom_Taxonomy {} class Plugin_Options_Page {} class Plugin_API { protected static $instance = NULL; protected $objects; public static function get_instance() { NULL === self::$instance and self::$instance = new self; return self::$instance; } public function add_object( $name, $object ) { $this->objects[ $name ] = $object; } public function wp_head() { $this->objects['post_type']->wp_head_callback(); $this->objects['taxonomy']->wp_head_callback(); } }
Ora un altropluginpuò rimuovere quell'azione con…
remove_action( 'wp_head', array ( Plugin_API::get_instance(), 'wp_head' ) );
...e sei ancora libero dimodificare la struttura deltuoplugin quando vuoi.
Questa è solo un'idea,non l'ho usata. Mapotrebbe valere lapenaprovareper unplugin complesso conmolte classi. Non sono sicuro di comefunzionerà coni filtri,ma questi sono comunquepiùfacili da spostare.
L'aggiornamento di unnumero sconosciuto dimeta campi deipostpuòessere costoso. Non lotoccherei.
Class names are case insensitive in PHP (with one exception), so that should not be a problem.
Accessing your main plugin instance for a class is possible with a static method
get_instance()
(example). You don’t have to build a Singleton for that. And it should not break backwards-compatibility.If you had public methods in your old code and these methods have been used by third party code, you have to keep the exact signature. So either keep the method and pass the call through to the instance of the new class, or – if there are many such methods – use
__call()
to catch all these methods in one.(Update) Given your example of
remove_action()
… this is tricky. If you add this callback from another class now, there is no safe way to stay backwards compatible, because you cannot “watch”remove_action()
calls.
You could register the old callback and implement an Observer to be noticed if it has been removed.One idea I have been playing with for future projects: separate the public API from the inner logic.
Example: Create a class
Plugin_API
and pass all objects from your working code into that class when they are set up. When a method from that API is called, pass that call to the responsible object internally, without exposing your plugin structure to the public.Sample code
add_action( 'wp_loaded', array ( Plugin_Controller::get_instance(), 'plugin_setup' ) ); class Plugin_Controller { protected static $instance = NULL; public static function get_instance() { NULL === self::$instance and self::$instance = new self; return self::$instance; } public function plugin_setup() { $api = Plugin_API::get_instance(); $api->add_object( 'post_type', new Plugin_Custom_Post_Type ); $api->add_object( 'taxonomy', new Plugin_Custom_Taxonomy ); $api->add_object( 'options_page', new Plugin_Options_Page ); add_action( 'wp_head', array ( $api, 'wp_head' ) ); } } class Plugin_Custom_Post_Type {} class Plugin_Custom_Taxonomy {} class Plugin_Options_Page {} class Plugin_API { protected static $instance = NULL; protected $objects; public static function get_instance() { NULL === self::$instance and self::$instance = new self; return self::$instance; } public function add_object( $name, $object ) { $this->objects[ $name ] = $object; } public function wp_head() { $this->objects['post_type']->wp_head_callback(); $this->objects['taxonomy']->wp_head_callback(); } }
Now another plugin can remove that action with …
remove_action( 'wp_head', array ( Plugin_API::get_instance(), 'wp_head' ) );
… and you are still free to change your plugin structure whenever you want.
This is just an idea, I haven’t used it. But it could be worth a try for a complex plugin with lots of classes. Not sure how it will work with filters, but these are easier to move anyway.
Updating an unknown number of post meta fields can be expensive. I would not touch that.
-
Speravopotessi rispondere a questo!Grazie!Posso disturbarti a dare un'occhiata al codice diterzeparti diesempio che ho aggiunto?Posso ancoraimplementare la struttura dellatua classe demoe/o spostare `some_templates ()`in una classe separata senzainterromperla?Was hoping you might respond to this! Thanks! Could I trouble you to take a look at the example third-party code I've added? Could I still implement your demo class structure, and/or move `some_templates()` to a separate class without breaking that?
- 0
- 2013-03-03
- helgatheviking
-
@helgatheviking Vediilmio aggiornamento.@helgatheviking See my update.
- 0
- 2013-03-03
- fuxia
-
Graziemille!Non so se saròin grado diimplementarlo con questoparticolareplugin a causa ditutta la retrocompatibilità,ma saràmolto utileperilprossimo!Thanks so much! I don't know if I'll be able to implement it with this particular plugin because of all the back-compatibility, but this will be super handy for the next one!
- 0
- 2013-03-03
- helgatheviking
Comefaccio ad aggiornare unmiopluginpubblico senza rompereilpluginpertuttigli utentiesistenti.
Innanzitutto ,vorreimodificare la classe/spazio deinomi delplug-inprincipale,perché vorrei chefosse simile alle altre classi delplug-in cheestende.
Quindi vorrei cambiare
a
In secondo luogo ,l'intera classe vieneistanziatae salvatain una variabileglobale.
Da qualcheparte qui ho visto unbuonesempio di comeistanziare una classe senza unglobale (non riesco atrovarlo ora,ovviamente,#doh). Ilglobalepuòessere utilizzato dagli utentiper aggiungere/rimuovere unpaio dimodelli. C'è unmodoper sbarazzarsi delglobale senza rompere completamentei temi dellepersone chepotrebbero usarlopermanipolarei modelli?
Terzo ,in relazione a quanto sopra,ilmiofilepluginprincipale è diventatomoltograndee vorrei dividerloin pezziper lamia sanitàmentale. Tuttavia,seilmetodo
some_templates()
èinsome_class()
èpossibile spostarloinfront_end_class()
senza rompere le coseper utenti?Adesempio
Per sganciare un'azionenelmioplugin
Èpossibilemodificare la struttura della classee l'impostazione delle variabiliglobali senzainterromperlo? Comeposso avvisare lepersone che questo è cambiato?
_doing_it_wrong()
?Infine ,ho salvato alcunimetapost come "sì" rispetto a "no" alposto di unbooleano. Ha senso cambiarlo?