Kann ein Widget im Customizer "zum Einmalgebrauch" verwendet werden (dh deaktiviert werden, nachdem 1 Instanz hinzugefügt wurde)?

8

Ich bin auf der nächtlichen Suche nach einem benutzerdefinierten Einweg-Widget .

Sobald eine Instanz davon zu einem Seitenleistenfenster im Customizer hinzugefügt wurde , sollte das Steuerelement im Bereich "Verfügbare Widgets" als deaktiviert angezeigt werden (oder alternativ ganz verschwinden).

So würde es aussehen (beachten Sie das visuell deaktivierte Widget auf der rechten Seite):

…

Das benutzerdefinierte Widget ist registriert und alles, aber ich bin bei der Einweganforderung festgefahren.

Technische Daten

  • Skalierung ist kein Problem. Es ist in Ordnung, nur 1 registrierte Seitenleiste anzunehmen. Der Ansatz kann darin bestehen, die Verwendung des Widgets entweder auf 1 pro Seitenleiste oder auf 1 pro alle registrierten Seitenleisten zu beschränken - beide wären vorerst gleich gut.
  • Die Widgets-Seite im Backend ist kein Problem. Dies ist nicht erforderlich, um auf der Widgets- Seite unter Darstellung im Back-End gleich gut zu funktionieren . Es muss nur im Customizer funktionieren.

Fragen

  1. Vor etwa 250 Jahren waren alle Widgets einmalig. Kennt jemand einen legitimen Weg, um diese Zeiten zurückzubringen und ein benutzerdefiniertes Widget nur 1x über die Widget-API verwenden zu lassen?
  2. Wenn nicht (was ich annehme, nachdem ich eine ganze Reihe von Kerndateien durchgearbeitet habe), würde ich wahrscheinlich auf einen CSS-basierten Ansatz zurückgreifen (Zeigerereignisse, Pseudoelement-Overlay, was auch immer). Würde irgendeine Art von Seele meinem sehr begrenzten Customizer / JavaScript-Wissen mit einem grundlegenden Ansatz zum Hinzufügen / Entfernen einer dedizierten CSS-Klasse zum Widget-Steuerelement im "verfügbaren" Bereich (der rechts) helfen, sobald eine Instanz des Widgets vorhanden ist? wurde zur Seitenleiste hinzugefügt / entfernt?

Was ich bisher versucht habe

  • Durchsuchte einen ganzen Teil der Kerndateien.
  • Lesen Sie dies und das , aber keines scheint praktisch zu sein.
  • Bastelte an jQuery-Ereignissen widget-added, widget-updatedund widget-synced, aber verpasse ein Ereignis für "Widget gelöscht".

Vielen Dank im Voraus!


Update: Ich habe meinen Proof of Concept noch nicht in einem öffentlichen Repo veröffentlicht, würde es natürlich tun.

Lösung

Ich habe die von Kraftner unten freundlicherweise zur Verfügung gestellte Lösung in ein Proof-of-Concept-Plugin auf GitHub verpackt .

Klebepresse
quelle
Sie können auch einfach die klassische Widget-API verwenden, anstatt WP_Widgetbeispielsweise: gist.github.com/westonruter/7141599
Weston Ruter

Antworten:

5

Ansatz

Also habe ich mir das angeschaut und mein Ansatz ist folgender:

  1. Gehen Sie beim Starten des Customizers durch alle Seitenleisten und deaktivieren Sie das Widget, sobald Sie eine Verwendung finden
  2. Wenn eine Seitenleiste geändert wird, wiederholen Sie dies erneut.

Haftungsausschluss

Dies hat die folgenden Einschränkungen:

  1. Dies ist das erste Mal, dass ich mich mit der JS-API des Customizers beschäftige. Ich mache hier vielleicht ineffiziente Sachen, aber hey, es funktioniert;)
  2. Kümmert sich nur um den Customizer (wie in der Frage angegeben)
  3. Führt keine serverseitige Validierung durch. Es verbirgt lediglich die Benutzeroberfläche. Wenn Sie also befürchten, dass jemand die Benutzeroberfläche umgeht, ist dies unvollständig / unsicher.
  4. Das Deaktivieren des Widgets ist global - jede Verwendung in einer Seitenleiste deaktiviert das Widget global.

Der Code

Nachdem wir den Haftungsausschluss erstellt haben, schauen wir uns den Code an:

(function() {
    wp.customize.bind( 'ready', function() {

        var api = wp.customize,
            widgetId = 'foo_widget',
            widget = wp.customize.Widgets.availableWidgets.findWhere( { id_base: widgetId } );

        /**
         * Counts how often a widget is used based on an array of Widget IDs.
         *
         * @param widgetIds
         * @returns {number}
         */
        var countWidgetUses = function( widgetIds ){

            var widgetUsedCount = 0;

            widgetIds.forEach(function(id){

                if( id.indexOf( widgetId ) == 0 ){
                    widgetUsedCount++;
                }

            });

            return widgetUsedCount;

        };

        var isSidebar = function( setting ) {
            return (
                0 === setting.id.indexOf( 'sidebars_widgets[' )
                &&
                setting.id !== 'sidebars_widgets[wp_inactive_widgets]'
            );
        };

        var updateState = function(){

            //Enable by default...
            widget.set('is_disabled', false );

            api.each( function( setting ) {
                if ( isSidebar( setting ) ) {
                    //...and disable as soon as we encounter any usage of the widget.
                    if( countWidgetUses( setting.get() ) > 0 ) widget.set('is_disabled', true );
                }
            } );

        };

        /**
         * Listen to changes to any sidebar.
         */
        api.each( function( setting ) {
            if ( isSidebar( setting ) ) {
                setting.bind( updateState );
            }
        } );

        updateState();

    });
})( jQuery );

Nebenbemerkung: Verwenden Sie die customize_controls_enqueue_scriptsAktion, um das Skript hinzuzufügen.


Sie könnten dies wahrscheinlich erweitern, um es auf eine Basis pro Seitenleiste anstatt global zu beschränken. Ich würde sagen, hören Sie sich die Aktivierung einer Seitenleiste an und zählen Sie dann die Widgets in dieser Seitenleiste. Aber ich fand auch keine Zeit, mich damit zu befassen.

Kraftner
quelle
Fantastisch! Mir fehlen die Worte, das funktioniert wie ein Zauber und löst meinen Fall vollständig. Ich hätte kein voll funktionsfähiges Beispiel erwartet, vielen Dank!
Glueckpress
1
Gute Fragen (klare Erklärung, Screenshots, Leistungsnachweis) verdienen vollständige Antworten. Hinterlassen Sie diesen Kommentar als Hinweis für andere Personen, wie sie die richtigen Antworten auf ihre Fragen erhalten. ;)
Kraftner