Un widget dans le Customizer peut-il être «à usage unique» (c'est-à-dire désactivé après l'ajout d'une instance)?

8

Je suis en quête nocturne pour créer un widget personnalisé à usage unique .

Dès qu'une instance de celui-ci a été ajoutée à un panneau de la barre latérale dans le Customizer , son contrôle sur le panneau Widgets disponibles doit être affiché comme désactivé (ou bien disparaître complètement).

Voici à quoi cela ressemblerait (notez le widget visuellement «désactivé» à droite):

…

Le widget personnalisé est enregistré et tout, mais je suis coincé à l'exigence à usage unique.

Spécifications

  • L'échelle n'est pas un problème. Il est acceptable de supposer qu'une seule barre latérale enregistrée. L'approche peut être de limiter l'utilisation du widget soit 1 par barre latérale, ou à 1 pour tous serait tout aussi bien à la fois enregistrés sidebars pour l' instant.
  • La page Widgets sur le back-end n'est pas un problème. Cela n'est pas nécessaire pour fonctionner aussi bien sur la page Widgets sous Apparence sur le back-end. Il ne doit fonctionner que dans le Customizer.

Des questions

  1. Il y a environ 250 ans, tous les widgets étaient à «usage unique». Quelqu'un connaît-il un moyen légitime de ramener ces temps et de faire en sorte qu'un widget personnalisé ne soit utilisé qu'une seule fois via l'API Widget?
  2. Sinon (ce que je suppose après avoir creusé une bonne partie des fichiers de base), je m'en remettrais probablement à une approche basée sur CSS (événements de pointeur, superposition de pseudo-éléments, peu importe). Une âme aimable aiderait-elle mes connaissances très limitées de personnalisation / JavaScript avec une approche de base sur la façon d'ajouter / supprimer une classe CSS dédiée au contrôle de widget dans le panneau "disponible" (celui de droite) une fois qu'une instance dudit widget a été ajouté / supprimé au panneau de la barre latérale?

Ce que j'ai essayé jusqu'à présent

  • Parcourez une bonne partie des fichiers de base.
  • Lisez ceci et ceci , mais aucun ne semble pratique.
  • Bricolée avec des événements jQuery widget-added, widget-updatedet widget-synced, mais manquer un événement pour « un widget supprimé ».

Merci d'avance!


Mise à jour: Je n'ai pas encore mis ma preuve de concept sur un repo public, je le ferais, bien sûr.

Solution

J'ai enveloppé la solution aimablement partagée par kraftner ci-dessous dans un plugin de preuve de concept sur GitHub .

glueckpress
la source
Vous pouvez également simplement utiliser l'API widget classique au lieu de WP_Widget, par exemple: gist.github.com/westonruter/7141599
Weston Ruter

Réponses:

5

Approche

J'ai donc examiné cela et mon approche est la suivante:

  1. Lors du lancement du personnalisateur, parcourez toutes les barres latérales et désactivez le widget dès que vous en découvrez l'utilisation.
  2. Chaque fois qu'une barre latérale est modifiée, recommencez.

Avertissement

Cela présente les limitations suivantes:

  1. C'est la première fois que je tente de jouer avec l'API JS du Customizer. Donc je fais peut-être des trucs inefficaces ici, mais bon, ça marche;)
  2. Ne se soucie que du Customizer (comme indiqué dans la question)
  3. Ne fait aucune sorte de validation côté serveur. Il masque simplement l'interface utilisateur, donc si vous craignez que quelqu'un contourne l'interface utilisateur, cela est incomplet / peu sûr.
  4. La désactivation du widget est globale - toute utilisation dans n'importe quelle barre latérale désactive le widget globalement.

Le code

Maintenant que la clause de non-responsabilité est terminée, examinons le code:

(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 );

Sidenote: utilisez l' customize_controls_enqueue_scriptsaction pour ajouter le script.


Vous pouvez probablement l'étendre pour le limiter à travailler sur une base par barre latérale au lieu de globalement. Je dirais écouter l'activation d'une barre latérale, puis compter les widgets de cette barre latérale. Mais je n'ai pas trouvé le temps d'examiner cela aussi.

kraftner
la source
Fantastique! Je suis à court de mots, cela fonctionne comme un charme et résout complètement mon cas. Je ne m'attendais pas à un exemple de travail complet, merci beaucoup!
glueckpress
1
Les bonnes questions (explication claire, captures d'écran, preuve d'effort) méritent des réponses complètes. Laisser ce commentaire comme un indice à d'autres personnes sur la façon d'obtenir des réponses appropriées à leurs questions. ;)
kraftner