In deze zelfstudie zullen we onder de motorkap van de WordPress-tekstwidget kijken om het proces van ontdekken een widget maken die kan worden toegevoegd aan meerdere widgetlocaties.
Als je de basisprincipes van programmeren in PHP kent, is het maken van een WordPress-widget helemaal niet moeilijk. Ik heb de basis besproken in een eerdere tutorial, The Anatomy of a WordPress Plugin - het is een goed idee om die eerst te controleren voordat je verder leest, als je nog geen widget hebt gebouwd.
Hoewel die basismanier om een widget te maken goed genoeg is voor veel plug-ins, heeft dit één belangrijk nadeel: de widget kan slechts aan één slot in een blog worden toegevoegd.
Als u de widget aan een van de zijbalken toevoegt, verdwijnt de knop "Toevoegen" van de widget en kan de widget niet aan een andere sleuf worden toegevoegd voordat deze uit de eerste wordt verwijderd.
In sommige gevallen is dat geen probleem, omdat de aard van de widget is dat deze slechts één keer wordt weergegeven. Het is bijvoorbeeld best OK om het blogarchief op één plek in de lay-out te vermelden. Maar er zijn veel gevallen waarin meer dan één instantie zeer nuttig kan zijn. Een voorbeeld hiervan is de tekstwidget die gebundeld is met WordPress.
De tekstwidget is een eenvoudige widget waarmee u een koptekst en een tekst kunt opgeven, waarbij ook HTML wordt toegestaan, en de inhoud ervan wordt weergegeven in de zijbalk van de blog. Vanwege deze eenvoud kan de widget voor een breed scala aan doeleinden worden gebruikt. In de volgende afbeelding - een screenshot van mijn persoonlijke blog - kunt u bijvoorbeeld zien hoe ik de tekstwidget eerst in de zijbalk gebruik om een welkomsttekst weer te geven en vervolgens opnieuw om enkele advertenties onder aan de zijbalk weer te geven. In WordPress-documentatie worden widgets zoals deze genoemd "Multi-widgets."
Omdat WordPress een open source-project is, kunnen we de broncode onderzoeken en gebruiken als referentie voor onze eigen projecten. Voor deze zelfstudie betekent dit dat we de tekstwidget van dichterbij kunnen bekijken en kunnen zien hoe deze is geïmplementeerd, door hem als een voorbeeld te gebruiken om onze eigen widgets om te zetten in multi-widgets.
De eerste stap is om te zoeken in de WordPress-codebase en de tekstwidget te vinden. Het is een interessante stap en ik raad je aan hier en daar ook andere bestanden te bekijken om een algemene indruk te krijgen van wat er zich afspeelt op het blogplatform..
Maar als je gewoon niet kunt wachten om actie te ondernemen, vind je hier de widgetcode:
wordpress / wp-includes / widgets.php
Open het bestand en scroll helemaal naar beneden, rond regel 1958 (in versie 2.7.1) en daar verborgen in het midden van de broncode, u vindt een voorbeeldwidget, voorzien van commentaar en het label "Patroon voor meerdere widgets (laat meerdere instanties toe, zoals de tekstwidget)."
In het begin kan de voorbeeldcode er nogal afschrikwekkend uitzien, dus we zullen het regel voor regel doornemen, zodat we de ideeën begrijpen waaromheen het patroon is gebouwd. De codefragmenten in deze zelfstudie zijn gekopieerd van het voorbeeldpatroon, maar ik heb hier en daar een paar kleine wijzigingen aangebracht om de code gemakkelijker te kunnen volgen (voornamelijk het splitsen van lange lijnen naar kortere). Afgezien van die kleine aanpassingen, is de broncode precies dezelfde als die je zult vinden bij het openen widgets.php
van de WordPress codebase.
Wanneer de gebruiker op de knop "Wijzigingen opslaan" in het menu Widgets klikt, verzamelt WordPress de formulierparameters van elke widget in de zijbalken en stuurt deze naar elk van de geregistreerde widgets. Deze functie maakt het maken van multi-widgets mogelijk: als de widgetcontrollerfunctie wordt gewaarschuwd om een widgetinstantie op te slaan, worden alle parameters hieraan doorgegeven en kan deze elke instantie van dit widgettype in één keer bijwerken, nieuwe toevoegen en toevoegen ongebruikte exemplaren verwijderen indien nodig.
We zullen de details van het spaarproces in korte tijd bekijken, maar eerst is een goede plaats om te beginnen kijken naar hoe de widgetgegevens voor een multi-widget worden opgeslagen, door te kijken naar het gedeelte van de code waar de gegevens worden gebruikt . Hier is de code voor de methode die wordt gebruikt om een exemplaar van de voorbeeldwidget weer te geven:
$ widget_args); $ widget_args = wp_parse_args ($ widget_args, array ('number' => -1)); extract ($ widget_args, EXTR_SKIP); // Gegevens moeten worden opgeslagen als array $ options = get_option ('widget_many'); als (! isset ($ options [$ number])) terugkomt; echo $ before_widget; // Doe dingen voor deze widget, teken gegevens van $ opties [$ nummer] echo $ after_widget; ?>
De eerste parameter die is doorgegeven aan de widget-renderfunctie, $ args
, bevat algemene widgetinstellingen, zoals wat moet worden afgedrukt voor en na de widget en hoe de widgetkop moet worden opgemaakt. De code op regel 3 wordt gebruikt om die informatie op te delen in lokale variabelen, waaruit $ before_widget
en $ after_widget
worden in het voorbeeld gebruikt.
De tweede parameter, $ widget_args
is interessanter voor ons: het bevat de id van de widget-instantie die moet worden weergegeven. Regel 4 tot en met 7 zijn er om ervoor te zorgen dat de parameter in een correct formaat komt, en dat uiteindelijk, na de extract
oproep op regel 7 kunnen we de widgetindex vinden in de lokale variabele $ number
.
Net als widget-instellingen voor een eenvoudige, eenmalige widget, worden de instellingen voor een widgetinstantie opgeslagen als een array met sleutel / waarde-paren voor elke instelling. Maar omdat we nu meerdere instanties moeten opslaan, in plaats van elke array met een eigen aanroep op te slaan update_option
, we plaatsen ze allemaal in één array met behulp van de instantie-ID ($ number
) als de index en sla het hele ding op met de id van het widgettype.
In het bovenstaande voorbeeld hebben we een widget met de naam 'widget_many
", en laten we zeggen dat we er drie exemplaren van hebben toegevoegd aan onze blogzijbalk.Tijdens het weergeven van een ervan, krijgen we eerst een array met alle widget_many
instanties door te bellen get_option (widget_many);
(regel 10) en zoek vervolgens de gegevens voor de huidige instantie uit die array (regel 16).
De voorbeeldcode van toont niet de details van wat u met de gegevens zou moeten doen, dus laten we de werkelijke tekstwidget bekijken voor meer inzicht:
$ widget_args); $ widget_args = wp_parse_args ($ widget_args, array ('number' => -1)); extract ($ widget_args, EXTR_SKIP); $ options = get_option ('widget_text'); als (! isset ($ options [$ number])) terugkomt; $ title = apply_filters ('widget_title', $ options [$ number] ['title']); $ text = apply_filters ('widget_text', $ options [$ number] ['text']); ?>
Op regels 13 en 14 kunt u zien hoe de twee parameters die nodig zijn voor de tekstwidget worden gelezen uit de opties die worden gebruikt $ number
als instantie-ID. En op de volgende tien regels worden de parameters op het scherm weergegeven.
Door de widgetweergavefunctie te analyseren, hebben we nu de basisinformatie achter het opslaan van de gegevens voor een multi-widget ontdekt:
Nu zullen we nader kijken en de trucs en kanttekeningen bekijken.
Met dezelfde aanpak als hiervoor, zullen we nu kijken naar de functie die wordt gebruikt voor het weergeven en verwerken van de instellingenformulieren en regel voor regel doorlopen. Deze functie, widget_many_control
, is de functie die de instellingen opslaat en het instellingenformulier voor de voorbeeldwidget "widget_many" rendert. Het wordt eenmaal voor elk genoemd widget_many
bijvoorbeeld altijd de instantie-id doorgeven $ widget_args
.
Aangezien de functie deel uitmaakt van de verwerking van formulierinzendingen, is de $ _POST
array bevat alle parameters die zijn verzonden met behulp van het widgetbewerkingsformulier.
$ widget_args); $ widget_args = wp_parse_args ($ widget_args, array ('number' => -1)); extract ($ widget_args, EXTR_SKIP);
Op de eerste regels van de functie ziet u iets vertrouwd (regels 6-9). Dit is hetzelfde stuk code dat werd gebruikt in de rendering-functie om ervoor te zorgen $ number
is geïnitialiseerd met de numerieke id van de huidige widgetinstantie.
Maar zoals je snel zult merken, hebben we die index voor niets anders nodig dan het bewerken van de widget, omdat we altijd elke instantie van het widgettype widget_many in één lus opslaan.
Vervolgens halen we de huidige widget-instellingen op en maken we ze als ze niet bestaan:
$ options = get_option ('widget_many'); if (! is_array ($ options)) $ options = array ();
Wanneer u uw eigen widget implementeert, vergeet dan niet om de sleutel te veranderen, widget_many
naar de id van uw eigen widget. Afgezien daarvan kan deze code opnieuw worden gebruikt zoals ze is. Op regels 2 en 3 zorgt de code voor het geval wanneer we de eerste widgetinstantie van dit type toevoegen door een lege optieschare te maken voor gebruik.
Als er al ten minste één instantie is opgeslagen, krijgen we die wel get_option
en kan doorgaan met het updaten van de instellingen als een formulier is ingediend:
if (! $ updated &&! empty ($ _ POST ['sidebar']))
De bovenstaande regel heeft twee functies: het controleert of gegevens zijn gepost ("!leeg ($ _ POST [ 'sidebar'])
") en zorgt ervoor dat instanties van dit widgettype slechts één keer worden afgehandeld.
Het widget-systeem roept de widget-afhandelingsfunctie eenmaal per widget-instantie aan, maar omdat we moeten zorgen voor zaken als het toevoegen en verwijderen van nieuwe widget-instanties, kunnen we dat niet doen zonder alle widgets van dit type die bestaan te kennen. Dit is de reden waarom de aanpak is om elke widgetinstantie van dit type bij de eerste instantie bij te werken en vervolgens de algemene variabele in te stellen $ bijgewerkt
naar true, zodat de volgende instantie de update niet opnieuw uitvoert.
// Vertelt ons welke zijbalk de gegevens in $ sidebar = (tekenreeks) $ _POST ['zijbalk'] plaatst; $ sidebars_widgets = wp_get_sidebars_widgets (); if (isset ($ sidebars_widgets [$ sidebar])) $ this_sidebar = & $ sidebars_widgets [$ sidebar]; else $ this_sidebar = array (); foreach ($ this_sidebar as $ _widget_id) $ widget = $ wp_registered_widgets [$ _ widget_id]; if ('widget_many' == $ widget ['callback'] && isset ($ widget ['params'] [0] ['number'])) $ widget_number = $ widget ['params'] [0] [' aantal']; if (! in_array ("many- $ widget_number", $ _POST ['widget-id'])) unset ($ options [$ widget_number]); // Compileer gegevens van $ widget_many_instance $ widget_data = (array) $ _POST ['widget-many']; foreach ($ widget_data als $ widget_number => $ widget_many_instance) if (! isset ($ widget_many_instance ['something']) && isset ($ options [$ widget_number])) // gebruiker klikte annuleren doorgaan; $ something = wp_specialchars ($ widget_many_instance ['something']); $ options [$ widget_number] = array ('iets' => $ iets); update_option ('widget_many', $ opties); $ updated = true; // Zodat we dit niet meer dan één keer meemaken
Dit codefragment bekijkt eerst alle widgets die zijn opgeslagen in de zijbalk die wordt bijgewerkt (regels 2-8) en gaat vervolgens door de lijst om alles te verwijderen dat overeenkomt met de widget-ID van dit widgettype (regels 10-18).
$ _POST ( "sidebar")
(regel 2) bevat de id van de zijbalk. Op deze manier wordt de widget ook uit de gegevens verwijderd als de gebruiker een widget heeft verwijderd. En door alles te verwijderen, zorgen we ervoor dat we niet per ongeluk duplicaten achterlaten, bijvoorbeeld als de id van een widget is gewijzigd tussen updates.
Nadat we alles hebben verwijderd, beginnen we met het toevoegen van de widgets die door de gebruiker zijn gepost. In het geposte formulier is er een array met alle gegevens voor elk exemplaar van het widgettype. De array is als volgt georganiseerd:
['widget-many'] => [0] => params voor widget instantie 0 (array), [1] => params voor widget instantie 1 (array), ...
Op regels 23-31 worden de widgetinstantie-gegevens die zijn ingediend door de code doorgelust en worden de instellingen voor elke instantie gemaakt (regels 29 en 30). Omdat dit slechts een voorbeeldcode is, maakt het opslagonderdeel gebruik van plaatshoudergegevens zoals "iets". Laten we dus opnieuw naar de tekstwidget kijken om te zien hoe dit werkt met echte gegevens:
$ title = strip_tags (stripslashes ($ widget_text ['title'])); if (current_user_can ('unfiltered_html')) $ text = stripslashes ($ widget_text ['text']); else $ text = stripslashes (wp_filter_post_kses ($ widget_text ['text'])); $ options [$ widget_number] = compact ('titel', 'tekst');
De tekstwidget heeft twee parameters: titel
en tekst
. De $ widget_text
variabele in dit stuk code wordt op dezelfde manier gebruikt als $ widget_many_instance
in de voorbeeldcode die we hebben gevolgd: deze bevat de gegevens die zijn gepost voor een specifiek exemplaar van de widget.
In het voorbeeld van de tekstwidget ziet u ook enkele interessante beveiligingsfuncties waarvan u misschien een beetje meer wilt kijken bij het ontwikkelen van uw eigen widgets. Voor deze zelfstudie is het echter voldoende om de inhoud van de variabelen te zien $ title
en $ text
worden gelezen uit de geplaatste array en vervolgens opgeslagen als een array naar de opties van de widget op regel 6.
Als je je afvraagt over de compact()
functie, het is het tegenovergestelde van extract()
, en neemt de lokale variabelen waarvan de namen werden doorgegeven als parameters en verandert ze in een array met de namen als sleutels.
Eindelijk het nieuwe $ options
array wordt opgeslagen als de gegevens voor de widget, widget_many
in de voorbeeldcode of widget_text
in de tekstwidget, met behulp van de update_option ()
functie.
Het laatste wat overblijft in de functie widget-instellingen is het tekenen van het formulier voor deze widget-instantie. Dit formulier wordt niet op het scherm weergegeven zoals het is, maar WordPress converteert het later naar een echte vorm, met behulp van JavaScript-magie. De onderstaande code is van de sjablooncode, dus deze gebruikt $ iets
om de widgetgegevens weer te geven. In de tekstwidget wordt deze vervangen door $ title
en $ text
, en in je eigen widget met alles wat je nodig hebt om op te slaan.
Het is belangrijk om op te merken dat, hoewel de besparing voor elke instantie in één keer wordt gedaan, het hier weergegeven formulier slechts voor één instantie is. Hier gebruiken we de id van de widgetinstantie die aan het begin van de functie is ingelezen.
if (-1 == $ nummer) $ something = "; $ number = '% i%'; else $ something = attribute_escape ($ options [$ number] ['something']);
Op de bovenstaande regels controleert de widget eerst of een geldig widgetnummer is opgegeven of niet. Zo niet, en $ number
was ingesteld op de standaardwaarde -1, alle gegevens moeten worden ingesteld op standaardwaarden. Anders krijgen we de gegevens van de $ options
array en gebruik deze om het formulier te vullen met de huidige instellingen. Dit is leuk om te doen, zodat de gebruiker de widget niet altijd hoeft te bewerken vanaf een lege lei.
En dan is het formulier zelf zo opgebouwd dat het in een array kan worden ingelezen wanneer het in de widget-afhandelingscode wordt geplaatst: de formulieringangen worden genoemd volgens het patroon widget-many [$ number] [iets]
waar $ number
is het nummer van deze widgetinstantie en iets
is de naam van de parameter die moet worden opgeslagen. WordPress parseert dit vervolgens in de arraystructuur die eerder is beschreven wanneer de gebruiker het formulier verzendt.
Het formulier heeft geen verzendknop omdat alle widgets worden opgeslagen met dezelfde verzendknop die wordt aangeboden door WordPress.
Om WordPress een widget in de lijst met widgets te tonen, moet u het registreren door WordPress te vertellen welke functies moeten worden gebruikt voor het renderen van de widget en het bijbehorende instellingenformulier. De manier waarop dit wordt gedaan voor multi-widgets is niet zo verschillend van gewone widgets. Het enige verschil is de manier waarop de ID van de widget wordt gedefinieerd: In $ control_ops
(regel 7), vertellen we WordPress om meerdere instanties in te schakelen en om alle widgetinstanties aan een id te koppelen "veel"
naar dit widget type.
function widget_many_register () if (! $ options = get_option ('widget_many')) $ options = array (); $ widget_ops = array ('classname' => 'widget_many', 'description' => __ ('Widget waarmee meerdere instanties mogelijk zijn')); $ control_ops = array ('width' => 400, 'height' => 350, 'id_base' => 'many'); $ name = __ ('Many'); $ registered = false; foreach (array_keys ($ options) as $ o) // Oude widgets kunnen om welke reden dan ook null-waarden hebben als (! isset ($ options [$ o] ['something'])) doorgaan; // $ id moet eruit zien als $ id_base - $ o $ id = "many- $ o"; // Vertaal nooit een id $ registered = true; wp_register_sidebar_widget ($ id, $ name, 'widget_many', $ widget_ops, array ('number' => $ o)); wp_register_widget_control ($ id, $ name, 'widget_many_control', $ control_ops, array ('number' => $ o)); // Als er geen zijn, registreren we de // existentie van de widget met een generieke template als (! $ Geregistreerd) wp_register_sidebar_widget ('many-1', $ name, 'widget_many', $ widget_ops, array ('number' = > -1)); wp_register_widget_control ('many-1', $ name, 'widget_many_control', $ control_ops, array ('number' => -1)); // Dit is belangrijk add_action ('widgets_init', 'widget_many_register');
In de bovenstaande functie registreren we eerst alle bestaande widgets van dit type en slaan we de overblijfselen over die geen geldige gegevens bevatten (regels 11-23) en als er dan nog geen exemplaar beschikbaar is, registreer dan een standaardsoort om zeker te zijn de widget is geregistreerd en beschikbaar in de zijbalk (regels 27-32).
Als laatste, cruciale stap, op regel 34, haken we de widget-initialisatiefunctie aan de widgets_init
gebeurtenis zodat WordPress het zal noemen als het tijd is om alle widgets te initialiseren. Zonder deze functie zouden we geen functionaliteit zien van de widget die we net hebben geanalyseerd, omdat geen enkel onderdeel van de code ooit zou worden aangeroepen.
In de bovenstaande fragmenten heb ik bewust een deel van de code weggelaten om dingen leesbaarder te maken, zodat je de stukken niet gewoon kunt kopiëren en samenvoegen. In plaats daarvan moet u diezelfde code gaan kopiëren vanuit uw WordPress-installatie.
Daarna hoeft u alleen maar uw eigen functionaliteit in te voeren, en daar hebt u het: uw eigen multi-widget.