¿Puede un widget en el Personalizador ser de "uso único" (es decir, deshabilitado después de que se haya agregado 1 instancia)?

8

Estoy en una búsqueda nocturna para crear un widget personalizado de un solo uso .

Tan pronto como se haya agregado una instancia a un panel de barra lateral en el Personalizador , su control en el panel de Widgets disponibles debería mostrarse como deshabilitado (o alternativamente, desaparecer por completo).

Así es como se vería (observe el widget visualmente "deshabilitado" a la derecha):

...

El widget personalizado está registrado y todo, pero estoy atascado en el requisito de un solo uso.

Especificaciones

  • La escala no es un problema. Está bien asumir solo 1 barra lateral registrada. El enfoque puede ser limitar el uso del widget a 1 por barra lateral, o a 1 por todas las barras laterales registradas, ambos estarían igualmente bien por ahora.
  • La página de widgets en el back-end no es un problema. No es necesario que funcione igual de bien en la página de widgets en Apariencia en el back-end. Solo tiene que funcionar en el Personalizador.

Preguntas

  1. Hace unos 250 años, todos los widgets solían ser de "un solo uso". ¿Alguien sabe de una forma legítima de recuperar esos tiempos y hacer que un widget personalizado se use solo 1x a través de la API de widgets?
  2. De lo contrario (lo que supongo después de haber excavado una buena cantidad de archivos principales), probablemente diferiría a un enfoque basado en CSS (eventos de puntero, superposición de pseudoelementos, lo que sea). ¿Podría algún tipo de alma ayudar a mi conocimiento muy limitado de Customizer / JavaScript con un enfoque básico sobre cómo agregar / eliminar una clase CSS dedicada al control del widget en el panel "disponible" (el de la derecha) una vez que una instancia de dicho widget tiene ha sido agregado / eliminado al panel de la barra lateral?

Lo que probé hasta ahora

  • Excavado en una buena parte de los archivos principales.
  • Lea esto y esto , pero ninguno parece práctico.
  • Vanamente con eventos de jQuery widget-added, widget-updatedy widget-synced, aunque se pierda un evento para “widget de borrado”.

Muchas gracias de antemano!


Actualización: Todavía no he puesto mi prueba de concepto en un repositorio público, lo haría, por supuesto.

Solución

Envolví la solución amablemente compartida por kraftner a continuación en un complemento de prueba de concepto en GitHub .

prensa de pegamento
fuente
También puede usar la API de widgets clásica en lugar de WP_Widget, por ejemplo: gist.github.com/westonruter/7141599
Weston Ruter

Respuestas:

5

Acercarse

Así que he investigado esto y mi enfoque es este:

  1. Al iniciar el personalizador, recorra todas las barras laterales y desactive el widget tan pronto como encuentre algún uso.
  2. Cada vez que se cambie una barra lateral, vuelva a hacerlo.

Descargo de responsabilidad

Esto tiene las siguientes limitaciones:

  1. Esta es la primera vez que incursiono en jugar con la API JS del Personalizador. Así que podría estar haciendo cosas ineficientes aquí, pero bueno, funciona;)
  2. Solo se preocupa por el Personalizador (como se indica en la pregunta)
  3. No hace ningún tipo de validación del lado del servidor. Simplemente oculta la interfaz de usuario, por lo que si le preocupa que alguien la eluda, esto es incompleto / inseguro.
  4. La desactivación del widget es global: cualquier uso en cualquier barra lateral desactiva el widget globalmente.

El código

Ahora que tenemos el descargo de responsabilidad, veamos el código:

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

Nota al margen: use la customize_controls_enqueue_scriptsacción para agregar el guión.


Probablemente podría extender esto para limitarlo a trabajar en una base por barra lateral en lugar de globalmente. Yo diría que escuche la activación de una barra lateral y luego cuente los widgets en esa barra lateral. Pero no encontré tiempo para investigar eso también.

Kraftner
fuente
¡Fantástico! No tengo palabras, esto funciona a las mil maravillas y resuelve mi caso por completo. No hubiera esperado un ejemplo de trabajo completo, ¡muchas gracias!
glueckpress
1
Las buenas preguntas (explicación clara, capturas de pantalla, prueba de esfuerzo) merecen respuestas completas. Dejando este comentario como una pista para que otras personas obtengan respuestas adecuadas a sus preguntas. ;)
kraftner