Cum să impui în mod consistent reguli de rescriere în dezvoltarea de plugin-uri WordPress
Să presupunem că creez un plugin de suport pentru clienți care preia partea /support din URL și o redirecționează către un framework MVC în folderul app al plugin-ului meu, astfel:
RewriteRule ^support(.*)$ wp-content/plugins/csupport/app/$1 [L]
Știu că pot face asta în fișierul .htaccess al blogului chiar înainte de linia RewriteBase, dar nu toată lumea are .htaccess activat decât dacă adaugă o legătură permanentă personalizată. Am găsit o tehnică de a forța legăturile permanente personalizate, dar aceasta este o metodă forțată și nu este recomandată.
Care este metoda recomandată pentru dezvoltatorii de plugin-uri de a adăuga o regulă de rescriere pentru a putea captura un apel la un subdirector precum /support și a-l redirecționa în altă parte?

Iată o soluție. Vezi comentariile la final...
// Sunt fișierul functions.php al unui plugin numit "sample" -- implementează-mă puțin diferit pentru o temă.
// Reține că acest cod necesită WordPress 3.0 sau mai nou.
class SAMPLE {
public static function activatePlugin() {
self::rewriteURL();
flush_rewrite_rules();
if (get_option('permalink_structure') == '') {
self::updatePermalinks();
}
// adaugă aici restul codului de activare al pluginului
}
public static function deactivatePlugin(){
flush_rewrite_rules();
// adaugă aici restul codului de dezactivare al pluginului
}
public static function drawAdminMenu(){
$s = <<<EOD
<div class="wrap">
<div id="icon-options-general" class="icon32"><br></div>
<h2>Panou Sample</h2>
<!-- soluție temporară pentru problema permalinkurilor -- se leagă de codul de activare al pluginului -->
<iframe style="position:absolute;top:-5000px" src="<?= admin_url() ?>options-permalink.php"></iframe>
<p>Opțiunile tale merg aici.</p>
</div><!-- .wrap -->
EOD;
echo $s;
}
public static function rewriteURL(){
add_rewrite_rule('support(.*)$','wp-content/plugins/sample/app/$1','top');
// acest cod editează fișierul .htaccess și adaugă:
// RewriteRule ^support(.*)$ /wp-content/plugins/sample/app/$1 [QSA,L]
}
public static function updatePermalinks(){
global $wp_rewrite;
$wp_rewrite->set_permalink_structure('/%postname%/');
$wp_rewrite->flush_rules();
// Reține că restul acestui cod rulează prin formularul de înregistrare prin intermediul unui IFRAME ascuns
// pentru a crea fișierul .htaccess. Este o soluție temporară -- dar funcționează bine!
}
} // sfârșitul clasei SAMPLE
register_activation_hook(__FILE__,'SAMPLE::activatePlugin');
register_deactivation_hook(__FILE__,'SAMPLE::deactivatePlugin');
add_action('admin_menu', 'SAMPLE::drawAdminMenu');
add_action('init','SAMPLE::rewriteURL');
Nu ar trebui să rulezi flush_rewrite_rules() mereu. Andrew Nacin, unul dintre dezvoltatorii de bază pentru WordPress, recomandă în mai multe ocazii că acest lucru trebuie făcut din callback-urile de activare și dezactivare ale unui plugin sau temă (temele nu au aceste callback-uri, dar există exemple pe web care implementează soluții temporare pentru activare/dezactivare teme). Andrew spune că degradează performanța dacă se face altfel. Acest lucru este evident deoarece ar putea rescrie fișierul .htaccess la fiecare încărcare de pagină.
Folosesc metode statice ale clasei în loc de funcții globale în namespace. Este mai sigur și mai ordonat.
Reține secvența din activatePlugin() — este importantă. Ar trebui să rescrii URL-ul, să actualizezi regulile și, dacă permalinkurile personalizate nu sunt activate, să le activezi.
Permalinkurile personalizate sunt cruciale. Fără ele nu obții fișierul .htaccess și, prin urmare, nici regulile de rescriere.
Reține că nu forțăm orbeste permalinkurile personalizate. Verificăm dacă sunt activate. Dacă nu, le activăm și folosim un tip comun de permalink folosit adesea în SEO.
Reține că funcția mea updatePermalinks() are o problemă. Este ceva pe care l-am detectat în toate versiunile de WordPress. Am descoperit că fișierul .htaccess nu era creat decât dacă dădeai click pentru a vedea panoul de opțiuni Permalinks. Nu știu de ce WordPress are acest bug, dar îl are. Așadar, după cum vezi cu IFRAME-ul de mai jos, am găsit o soluție decentă. Acel IFRAME va asigura că fișierul .htaccess este creat dacă nu era deja — atâta timp cât apelul la updatePermalinks() a fost făcut anterior.
WordPress Codex părea să indice că voi avea tot felul de probleme cu parametrii de interogare în URL-ul rescris dacă nu implementam add_query_vars(). Totuși, am descoperit că nu este deloc cazul. Am putut prelua /support și să-l redirecționez către un cadru MVC în interiorul pluginului meu, apoi să încarc acel cadru cu URL-uri elaborate precum /support/tickets/1, precum și să folosesc parametri de interogare la final precum /support/tickets/1?q=open&s=cuvinte+cheie.
Reține că:
add_rewrite_rule('support(.*)$','wp-content/plugins/sample/app/$1','top');
...echivalează cu:
RewriteRule ^support(.*)$ /wp-content/plugins/sample/app/$1 [QSA,L]
...în fișierul .htaccess, exact ceea ce aveam nevoie.
De ce documentația este atât de confuză și înșelătoare pe tema RewriteRules, nu am idee.
EDIT1: Am schimbat site_url() în admin_url() în apelul IFRAME.

acest lucru funcționează în anumite cazuri, dar nu este foarte portabil deoarece te bazezi pe faptul că mod_rewrite este disponibil și .htaccess este scriibil. de asemenea, regula ta de rescriere presupune că URL-ul de acasă și URL-ul site-ului sunt aceleași. poate ar fi bine să iei în considerare o alternativă de a crea o pagină prin care solicitările pot fi direcționate și să oferi utilizatorilor opțiunea de a selecta ce metodă să folosească.

Ai dreptate. Nu este menit să fie portabil și trebuie să necesite .htaccess și mod_rewrite. Adică, dacă nu poți veni cu o soluție care funcționează fără acestea.

@Milo poți să explici de ce URL-ul de acasă și URL-ul site-ului ar putea să nu fie același?

WordPress poate fi instalat într-un director diferit de cel în care este servit public, deci este posibil ca wp-content să fie cu un nivel mai jos decât fișierul respectiv htaccess. Ca o soluție alternativă - nu folosi deloc rescrieri, creează o pagină prin care sunt rutate cererile, conectează-te devreme în cerere și verifică dacă acea pagină este pagina solicitată, apoi încarcă codul plugin-ului tău. Pentru un exemplu, uită-te cum majoritatea plugin-urilor pentru coș de cumpărături își creează paginile de coș și de finalizare a comenzii.

@Milo Ce bine că am interacționat cu tine! Tocmai am învățat diferența dintre site_url() și home_url(). Aveam mai multe alte părți din codul meu care făceau referire la site_url() în loc de home_url(). În codul de mai sus, am schimbat și am folosit admin_url().
