web-dev-qa-db-fra.com

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

Je suis dans une quête nocturne pour construire un widget personnalisé à usage unique .

Dès qu'une instance de celle-ci a été ajoutée à un panneau de la barre latérale dans le Customizer , son contrôle sur le panneau des widgets disponibles doit être affiché comme étant désactivé (ou, sinon, disparaître entièrement).

Voici à quoi cela ressemblerait (notez le widget visuellement "désactivé" sur la droite):

 … 

Le widget personnalisé est enregistré et tout, mais je suis bloqué à l'exigence d'utilisation unique.

Spécifications

  • L'échelle n'est pas un problème. Il n’est pas grave de supposer qu’un seul menu latéral est enregistré. L’approche peut consister à limiter l’utilisation du widget à 1 par barre latérale, ou à 1 par barre latérale {toutes} enregistrées - les deux seraient tout aussi bien pour le moment.
  • La page Widgets sur le back-end n'est pas un problème. Il n'est pas nécessaire que cela fonctionne aussi bien sur la page Widgets sous Apparence sur le back-end. Cela ne doit fonctionner que dans le Customizer.

Des questions

  1. Il y a environ 250 ans, tous les widgets étaient à "usage unique". Est-ce que quelqu'un connaît un moyen légitime de ramener ces moments et de faire en sorte qu'un widget personnalisé ne soit utilisé qu'une seule fois via l'API du widget?
  2. Si ce n’est pas le cas (ce que je suppose après avoir fouillé dans pas mal de fichiers de base), j’aurais probablement opté pour une approche basée sur CSS (événements de pointeur, superposition de pseudo-éléments, peu importe). Est-ce qu'une âme bienveillante aiderait mes très connaissances limitées en matière de personnalisation/JavaScript avec une approche de base sur la manière d'ajouter/de supprimer une classe CSS dédiée au contrôle de widget dans le panneau "disponible" (celui du droite) une fois qu'une instance dudit widget a été ajoutée/supprimée dans le panneau latéral?

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

  • Creuser dans une bonne partie des fichiers core.
  • Lisez ceci , et ceci , mais aucun ne semble pratique.
  • Bricolé avec les événements jQuery widget-added, widget-updated et widget-synced, mais manque un événement pour le "widget supprimé".

Merci beaucoup d'avance!


Mise à jour: Je n’ai pas encore mis ma preuve de concept sur une prise en pension publique.

Solution

J'ai présenté la solution gentiment partagée par kraftner ci-dessous dans un plug-in preuve de concept sur GitHub .

8
glueckpress

Approche

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

  1. Lorsque vous lancez le personnaliseur, parcourez toutes les barres latérales et désactivez le widget dès que vous en trouvez l’utilisation.
  2. Chaque fois qu'une barre latérale est modifiée, recommencez.

Avertissement

Cela a les limitations suivantes:

  1. C'est la première fois que je joue à l'API JS du Customizer. Donc, je pourrais faire des choses inefficaces ici, mais bon, ça marche;)
  2. Ne se soucie que du personnalisateur (comme indiqué dans la question)
  3. Ne fait aucune sorte de validation côté serveur. Elle ne fait que masquer l'interface utilisateur. Si vous craignez que quelqu'un la contourne, l'interface est incomplète/non sécurisée.
  4. La désactivation du widget est globale - toute utilisation dans une barre latérale désactive le widget de manière globale.

Le code

Maintenant que le Disclaimer est terminé, regardons 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 );

Note: Utilisez l'action customize_controls_enqueue_scripts pour ajouter le script.


Vous pourriez probablement étendre ceci pour le limiter à une base de travail par barre latérale plutôt que globale. Je dirais qu'il faut écouter l'activation d'une barre latérale, puis compter les widgets dans cette barre latérale. Mais je n'ai pas trouvé le temps de regarder cela aussi.

5
kraftner