Cum să structurezi un plugin
Aceasta nu este o întrebare despre cum să construiești un plugin WordPress. Mai degrabă, ce ghiduri, dacă există, ar putea fi aplicate pentru organizarea arhitecturii de fișiere a oricărui plugin.
Unele alte limbaje de programare sau biblioteci au modalități foarte stricte de organizare a directoarelor și fișierelor. Uneori acest lucru este deranjant și evidențiază libertatea pe care o oferă PHP, dar pe de altă parte plugin-urile WordPress sunt construite în orice mod determinat de autorul lor.
Nu există un răspuns corect, dar speranța mea este să rafinăm modul în care eu și alții construim plugin-uri pentru a le face mai prietenoase pentru alți dezvoltatori să le analizeze, mai ușor de depanat, mai ușor de navigat și posibil mai eficiente.
Întrebarea finală: care crezi că este cea mai bună modalitate de a organiza un plugin?
Mai jos sunt câteva structuri exemplu, dar în niciun caz nu este o listă exhaustivă. Simțiți-vă liberi să adăugați propriile recomandări.
Structura Implicită Presupusă
/wp-content/plugins/my-pluginmy-plugin.php
Metoda Model View Controller (MVC)
/wp-content/plugins/my-plugin/controllerController.php
/modelModel.php
/viewview.php
my-plugin.php
Cele trei părți ale MVC:
- Modelul interacționează cu baza de date, interogând și salvând date, și conține logica.
- Controlerul ar conține tag-uri de șablon și funcții pe care le-ar utiliza view-ul.
- View-ul este responsabil pentru afișarea datelor furnizate de model așa cum sunt construite de controller.
Metoda organizată pe tipuri
/wp-content/plugins/my-plugin/adminadmin.php
/assetscss/images/
/classesmy-class.php
/langmy-es_ES.mo
/templatesmy-template.php
/widgetsmy-widget.php
my-plugin.php
WordPress Plugin Boilerplate
Disponibil pe Github
Bazat pe API-ul pentru Plugin-uri, Standarde de Codare, și Standarde de Documentație.
/wp-content/plugins/my-plugin/admin/css/js/partialsmy-plugin-admin.php
/includesmy_plugin_activator.phpmy_plugin_deactivator.phpmy_plugin_i18n.phpmy_plugin_loader.phpmy_plugin.php
/languagesmy_plugin.pot
/public/css/js/partialsmy-plugin-public.php
LICENSE.txtREADME.txtindex.phpmy-plugin.phpuninstall.php
Metoda organizată liber
/wp-content/plugins/my-plugincss/images/js/my-admin.phpmy-class.phpmy-template.phpmy-widget.phpmy-plugin.php
Rețineți că toate plugin-urile sunt "controlere" conform standardelor WordPress.
Depinde de ce ar trebui să facă plugin-ul, dar în toate cazurile aș încerca să separ afișarea pe ecran de codul PHP cât mai mult posibil.
Iată o modalitate ușoară de a face acest lucru - mai întâi, definiți o funcție care încarcă template-ul:
function my_plugin_load_template(array $_vars){
// nu puteți lăsa locate_template să încarce template-ul vostru
// deoarece dezvoltatorii WP au făcut să nu puteți transmite
// variabile în template :(
$_template = locate_template('my_plugin', false, false);
// folosiți cel implicit dacă tema nu îl are
if(!_$template)
$_template = 'views/template.php';
// încărcați-l
extract($_vars);
require $template;
}
Acum, dacă plugin-ul folosește un widget pentru a afișa date:
class Your_Widget extends WP_Widget{
...
public function widget($args, $instance){
$title = apply_filters('widget_title', $instance['title'], $instance, $this->id_base);
// acest widget afișează ultimele 5 "filme"
$posts = new WP_Query(array('posts_per_page' => 5, 'post_type' => 'movie'));
if($title)
print $before_title . $title . $after_title;
// aici ne bazăm pe template pentru a afișa datele pe ecran
my_plugin_load_template(array(
// variabile pe care doriți să le expuneți în template
'posts' => $posts,
));
print $before_widget;
}
...
}
Template-ul:
<?php while($posts->have_posts()): $posts->the_post(); ?>
<p><?php the_title(); ?></p>
<?php endwhile; ?>
Fișiere:
/plugins/my_plugin/plugin.php <-- doar hook-uri
/plugins/my_plugin/widget.php <-- clasa widget, dacă aveți un widget
/themes/twentyten/my_plugin.php <-- template
/plugins/my_plugin/views/template.php <-- template de rezervă
Unde puneți CSS-ul, JS-ul, imaginile sau cum proiectați containerul pentru hook-uri este mai puțin important. Cred că este o chestiune de preferință personală.
Depinde de plugin. Acesta este structura mea de bază pentru aproape fiecare plugin:
my-plugin/
inc/
Orice fișiere PHP suplimentare specifice plugin-ului se află aici
lib/
Clase de bibliotecă, fișiere css, js și alte fișiere pe care le folosesc cu multe
plugin-uri se află aici
css/
js/
images/
lang/
Fișiere de traducere
my-plugin.php
readme.txt
Acesta ar fi ceva care ar merge în folderul lib.
Dacă este un plugin deosebit de complex, cu multă funcționalitate în zona de administrare, aș adăuga un folder admin pentru a conține toate acele fișiere PHP. Dacă plugin-ul face ceva precum înlocuirea fișierelor de temă incluse, poate exista și un folder template sau theme.
Deci, o structură de directoare ar putea arăta astfel:
my-plugin/
inc/
lib/
admin/
templates/
css/
js/
images/
lang/
my-plugin.php
readme.txt
Ai include și fișierele CSS și JS ale administratorului în folderul /admin? Astfel, având un alt /css și /js în /admin?
urok93
După părerea mea, cea mai ușoară, puternică și ușor de întreținut cale este utilizarea unei structuri MVC, iar WP MVC este conceput să facă scrierea plugin-urilor MVC foarte simplă (deși sunt puțin părtinitor...). Cu WP MVC, pur și simplu creezi modelele, view-urile și controllerele, iar restul este gestionat în spatele scenei pentru tine.
Se pot crea controllere și view-uri separate pentru secțiunile publice și cele de administrare, iar întregul cadru beneficiază de multe dintre caracteristicile native ale WordPress. Structura fișierelor și mare parte din funcționalitate sunt exact la fel ca în cele mai populare framework-uri MVC (Rails, CakePHP, etc).
Mai multe informații și un tutorial pot fi găsite aici:
Folosim un mix al tuturor metodelor. În primul rând, utilizăm Zend Framework 1.11 în pluginurile noastre și, din această cauză, a trebuit să folosim o structură similară pentru fișierele de clasă datorită mecanismului de autoload.
Structura pluginului nostru principal (care este folosit ca bază de toate pluginurile noastre) arată astfel:
webeo-core/
css/
images/
js/
languages/
lib/
Webeo/
Core.php
Zend/
/** fișiere ZF **/
Loader.php
views/
readme.txt
uninstall.php
webeo-core.php
- WordPress apelează fișierul
webeo-core.phpdin directorul rădăcină al pluginului. - În acest fișier setăm calea de includere PHP și înregistrăm hook-urile de activare și dezactivare pentru plugin.
- De asemenea, avem o clasă
Webeo_CoreLoaderîn acest fișier, care setează unele constante ale pluginului, inițializează autoloaderul de clasă și face un apel către metoda de setup a claseiCore.phpdin folderullib/Webeo. Acest lucru rulează pe hook-ul de acțiuneplugins_loadedcu o prioritate de9. - Clasa
Core.phpeste fișierul nostru de bootstrap pentru plugin. Numele este bazat pe numele pluginului.
După cum puteți vedea, avem un subdirector în folderul lib pentru toate pachetele noastre de furnizori (Webeo, Zend). Toate subpachetele din cadrul unui furnizor sunt structurate după modulul în sine. Pentru un nou formular de administrare Mail Settings, am avea următoarea structură:
webeo-core/
...
lib/
Webeo/
Form/
Admin/
MailSettings.php
Admin.php
Core.php
Form.php
Subpluginurile noastre au aceeași structură cu o singură excepție. Mergem cu un nivel mai adânc în folderul furnizorului pentru a rezolva conflictele de nume în timpul evenimentului de autoload. De asemenea, apelăm clasa de bootstrap a pluginului De ex. Faq.php cu prioritatea 10 în cadrul hook-ului plugins_loaded.
webeo-faq/ (folosește/extinde webeo-core)
css/
images/
js/
languages/
lib/
Webeo/
Faq/
Faq.php
/** toate fișierele de clasă relevante pentru plugin **/
views/
readme.txt
uninstall.php
webeo-faq.php
Probabil voi redenumi folderul lib în vendors și voi muta toate folderele publice (css, images, js, languages) într-un folder numit public în următoarea versiune.
Ca mulți au răspuns deja, chiar depinde de ceea ce ar trebui să facă plugin-ul, dar iată structura mea de bază:
my-plugin/
admin/
conține toate fișierele pentru administrare din back-end
js/
conține toate fișierele JavaScript pentru back-end
css/
conține toate fișierele CSS pentru back-end
images/
conține toate imaginile pentru back-end
admin_file_1.php fișier de funcționalități pentru back-end
admin_file_2.php alt fișier de funcționalități pentru back-end
js/
conține toate fișierele JavaScript pentru front-end
css/
conține toate fișierele CSS pentru front-end
inc/
conține toate clasele helper
lang/
conține toate fișierele de traducere
images/
conține toate imaginile pentru front-end
my-plugin.php fișierul principal al plugin-ului cu meta informații, include mostly, action și filter hooks
readme.txt
changelog.txt
license.txt
Prefer următoarea structură pentru plugin-uri, deși de obicei aceasta se schimbă în funcție de cerințele specifice ale plugin-ului.
wp-content/
plugins/
my-plugin/
inc/
Fișiere specifice doar pentru acest plugin
admin/
Fișiere pentru gestionarea sarcinilor administrative
lib/
Clase de bibliotecă/ajutătoare se află aici
css/
Fișiere CSS pentru plugin
js/
Fișiere JavaScript
images/
Imagini pentru pluginul meu
lang/
Fișiere de traducere
plugin.php
Acesta este fișierul principal care include/apelează alte fișiere
README
De obicei pun aici detalii despre licență, plus informații utile
Încă nu am creat un plugin WordPress care să necesite o arhitectură în stil MVC, dar dacă ar fi să o fac, aș organiza-o cu un director MVC separat, care să conțină view-uri/controlere/modele.
Toate plugin-urile mele urmează această structură, care pare să fie foarte asemănătoare cu ce fac majoritatea altor dezvoltatori:
plugin-folder/
admin/
css/
images/
js/
core/
css/
images/
js/
languages/
library/
templates/
plugin-folder.php
readme.txt
changelog.txt
license.txt
plugin-folder.php este de obicei o clasă care încarcă toate fișierele necesare din folderul core/. Cel mai adesea pe hook-ul init sau plugins_loaded.
Obișnuiam să prefixez toate fișierele mele, dar așa cum a menționat @kaiser mai sus, este cu adevărat redundant și am decis recent să renunț la această practică pentru viitoarele plugin-uri.
Folderul library/ conține toate bibliotecile externe de ajutor de care ar putea depinde plugin-ul.
În funcție de plugin, poate exista și un fișier uninstall.php în rădăcina plugin-ului. Totuși, de cele mai multe ori acest lucru este gestionat prin register_uninstall_hook().
Evident, unele plugin-uri s-ar putea să nu necesite fișiere de administrare sau template-uri etc., dar structura de mai sus funcționează pentru mine. În final, trebuie doar să găsești o structură care funcționează pentru tine și apoi să te ții de ea.
De asemenea, am un plugin de pornire, bazat pe structura de mai sus, pe care îl folosesc ca punct de plecare pentru toate plugin-urile mele. Tot ce trebuie să fac apoi este să caut și să înlocuiesc prefixele funcțiilor/claselor și să încep. Când mai prefixam fișierele, acesta era un pas în plus pe care trebuia să-l fac (și destul de enervant), dar acum trebuie doar să redenumesc folderul plugin-ului și fișierul principal al plugin-ului.
Logica mea este că, cu cât este mai mare plugin-ul, cu atât mai multă structură folosesc.
Pentru plugin-uri mari tind să folosesc MVC.
Folosesc acest punct de plecare și omit ceea ce nu este necesar.
controller/
frontend.php
wp-admin.php
widget1.php
widget2.php
model/
standard-wp-tables.php // dacă este necesar, împărțit în fișiere separate
custom-tabel1.php
custom-tabel2.php
view/
helper.php
frontend/
fisiere...php
wp-admin/
fisiere...php
widget1/
fisier...php
widget2/
fisier...php
css/
js/
imagini/
library/ //doar php, în principal pentru Zend Framework, din nou dacă este necesar
constants.php //tind să o folosesc des
plugin.php //fișier de inițializare
install-unistall.php //doar pentru plugin-uri mari
De asemenea, consultă acest boilerplate excelent pentru widget-uri WP. Oferă indicații valoroase privind structurile (chiar dacă nu există o clasă sau un folder pentru modele separate).
O abordare mai puțin comună pentru structurarea fișierelor și directorelor unui plugin este cea bazată pe tipul de fișier. Merită menționată aici pentru completitudine:
plugin-name/
js/
sparkle.js
shake.js
css/
style.css
scss/
header.scss
footer.scss
php/
class.php
functions.php
plugin-name.php
uninstall.php
readme.txt
Fiecare director conține doar fișiere de acel tip. Este important de menționat că această abordare are limitări atunci când aveți mai multe tipuri de fișiere .png .gif .jpg care ar putea fi mai bine organizate într-un singur director, de exemplu images/.
Am dezvoltat un șablon de repository GitHub pentru plugin-uri WordPress, încapsulând peste 10 ani de experiență într-o structură bine definită!
https://github.com/EdwardBock/wordpress-plugin-starterkit
Șablonul respectă standardele PSR-4 pentru a minimiza includerea de șiruri de caractere și utilizează namespace-uri pentru o denumire concisă a claselor și o clasă componentă de templating. De asemenea, include un fișier docker compose pentru a permite dezvoltarea plugin-ului în izolare. Dar poate fi plasat și într-un proiect existent, funcționând la fel de bine.
Bucurați-vă să explorați și nu ezitați să contribuiți!