Advertisement
  1. Code
  2. Creative Coding

Usar Backbone dentro del área de administración de WordPress: El front end

Scroll to top
Read Time: 11 min

Spanish (Español) translation by Eva Collados Pascual (you can also view the original English article)

Bienvenido a la segunda parte de Usar Backbone dentro del área de administración de WordPress. En la primera parte, configuramos el 'back-end' de nuestro plugin y ahora en la segunda parte terminaremos agregando nuestra funcionalidad del 'lado del cliente' o 'front-end'. Para obtener una visión general de lo que estamos construyendo en este tutorial junto con nuestra estructura de carpetas y archivos, por favor, revisa la primera parte.


1. Crear el archivo de plantilla

Dentro de la carpeta src, crea otra llamada Templates y un archivo dentro de esta llamado metabox.templ.php. Aquí es donde pondremos el HTML necesario para nuestra caja meta. También es una gran oportunidad para generar los datos JSON necesarios para nuestras respuestas.

Tus carpetas y archivos ahora deberían tener este aspecto.

files02

Crear la plantilla para una respuesta única

Echemos otro vistazo a lo que estamos creando. Puedes pensar en cada respuesta como un modelo de datos y, dado que usaremos plantillas del lado cliente para generar una vista para cada una, esa visualización puede reaccionar a los cambios dentro del modelo. Esto nos permite ser muy específicos al enlazar eventos con la interfaz de usuario y, naturalmente, conduce a un flujo de trabajo más sencillo una vez hayas conseguido meterlo en tu cabeza.

model-view

Dentro de nuestro recién creado metabox.templ.php, esta es la plantilla que usaremos para cada uno de nuestros modelos. Puedes ver que básicamente estamos ajustando algo de HTML en una etiqueta de script. Le damos a la etiqueta de script el atributo "type="text/template" para que el navegador no lo represente en la página. Este pequeño fragmento de HTML se usará más adelante para generar el marcado necesario para cada visualización. Usaremos las capacidades de plantilla integradas de Underscore para que los valores ajustados así sean reemplazados más adelante por datos en nuestros modelos.

1
<!-- src/templates/metabox.templ.php  -->
2
3
<!-- Template -->
4
<script type="text/template" id="inputTemplate">
5
	<label for="<%= answer_id %>"><%= index %>:</label>

6
	<input id="<%= answer_id %>" class="answers" size="30" type="text" name="<%= answer_id %>" value="<%= answer %>" placeholder="Answer for Question <%= index %> Here">
7
	<button disabled="true">Save</button>

8
</script>
9
<!-- End template -->

HTML base

Todavía dentro de src/templates/metabox.templ.php, aquí solo estamos colocando los contenedores que se poblarán con los campos de entradas de la plantilla anterior. Esto sucede después de que Backbone haya analizado los datos JSON necesarios para el modelo, así que por ahora esto es todo lo que necesitamos hacer aquí.

1
<!-- src/templates/metabox.templ.php  -->
2
<p>Enter the Answers below</p>
3
<div id="answerInputs"></div>
4
<div id="answerSelect">
5
	<span>Correct Answer:</span>
6
</div>
7
<p>
8
	<input name="save" type="submit" class="button button-primary button-small" value="Save all">
9
</p>

Dar salida al JSON

Lo último que se necesita dentro del archivo src/templates/metabox.templ.php, son los datos JSON que representan cada respuesta. Aquí estamos creando un objeto en el espacio de nombres global y luego asignando los valores que enviamos con la matriz $viewData. También me gusta guardar referencias a los contenedores que usaremos más adelante para no tener identificaciones en dos archivos separados.

1
<!-- src/templates/metabox.templ.php  -->
2
<script>
3
	window.wpQuiz = {};
4
	var wpq = window.wpQuiz;
5
	wpq.answers = <?= $answers ?>;
6
	wpq.answers.correct = <?= $correct ?>;
7
	wpq.answerSelect = '#answerSelect';
8
	wpq.answerInput = '#answerInputs';
9
	wpq.inputTempl = '#inputTemplate';
10
	wpq.post_id = <?= $post->ID ?>;
11
</script>

2. El JavaScript

Ok, si has llegado hasta aquí, has configurado con éxito tu plugin para permitir el uso de Backbone.js y tu caja meta está generando el marcado requerido y los datos JSON. Ahora es el momento de juntarlo todo y usar Backbone.js para organizar nuestro código del lado cliente. Es hora de cubrir lo siguiente:

  1. Crear una colección de modelos a partir de los datos JSON
  2. Uso de plantillas del lado cliente para construir una vista para cada modelo
  3. Observar los eventos de clic, tecla y pérdida de foco dentro de cada vista
  4. Guardar un modelo en la base de datos

Crea el archivo admin.js y colócalo en la carpeta js

La estructura de directorios final y los archivos deberían tener este aspecto.

files03

En primer lugar vamos a envolver todo lo que hacemos en una función que es invocada inmediatamente y pasar en jQuery para ser utilizado con el signo $, no voy a mostrar este contenedor en más fragmentos, así que asegúrate de poner todo lo que hay debajo dentro de él.

1
/* js/admin.js */
2
3
(function($) {
4
5
	/** Our code here **/
6
7
}(jQuery));

A continuación, necesitamos tener acceso a nuestros datos almacenados en el espacio de nombres global y también crear un nuevo objeto que almacenará nuestros objetos Backbone.

1
/* js/admin.js */
2
3
	var Quiz = { Views:{} };
4
	var wpq  = window.wpQuiz;

El modelo

El modelo representa una única respuesta. Dentro de su constructor estamos haciendo un par de cosas.

  1. Establecer un valor predeterminado para correcto como false
  2. Establecer la dirección URL que Backbone requiere para volver a guardar el modelo en la base de datos. Podemos acceder a la URL correcta gracias a WordPress probando la variable ajaxurl que está disponible en cada página de administración. También añadimos el nombre de nuestro método que maneja la solicitud ajax
  3. A continuación, estamos sobrescribiendo el método toJSON para anexar el ID de la entrada actual a cada modelo. Esto podría haberse hecho en el lado del servidor, pero lo he puesto aquí como un ejemplo de cómo se puede reemplazar lo que se guarda en el servidor (Esto puede ser muy útil, por eso lo he incluido aquí)
  4. Por último, en el método initialize, estamos comprobando si el modelo actual es la respuesta correcta comparando su ID con el ID de la respuesta correcta. Hacemos esto para que más adelante sepamos qué respuesta debe ser seleccionada por defecto
1
/* js/admin.js */
2
3
	Quiz.Model = Backbone.Model.extend({
4
		defaults : {
5
			'correct' : false
6
		},
7
		url : ajaxurl+'?action=save_answer',
8
		toJSON : function() {
9
			var attrs = _.clone( this.attributes );
10
			attrs.post_id = wpq.post_id;
11
			return attrs;
12
		},
13
		initialize : function() {
14
			if ( this.get( 'answer_id' ) === wpq.answers.correct ) {
15
				this.set( 'correct', true );
16
			}
17
		}
18
	});

La colección

Una colección es esencialmente solo un envoltorio para un montón de modelos y hace que trabajar con esos modelos sea muy fácil. Para nuestro pequeño ejemplo, no modificaremos la colección, a excepción de especificar qué modelo debe usar.

1
/* js/admin.js */
2
3
	Quiz.Collection = Backbone.Collection.extend({
4
		model: Quiz.Model
5
	});

El contenedor de los campos de entrada

Nuestra primera vista se puede considerar un contenedor para los campos de entrada individuales. No necesitamos declarar una plantilla o qué elemento HTML queremos que Backbone cree para nosotros en este caso, porque más adelante, cuando creamos una instancia de esta vista, le pasaremos el identificador de un div que creamos en el archivo de caja meta. A continuación, Backbone simplemente usará ese elemento como contenedor. Esta vista tomará una colección y para cada modelo de esa colección, creará un nuevo elemento de entrada (input) y lo anexará a sí mismo.

1
/* js/admin.js */
2
3
	Quiz.Views.Inputs = Backbone.View.extend({
4
		initialize:function () {
5
			this.collection.each( this.addInput, this );
6
		},
7
		addInput : function( model, index ) {
8
			var input = new Quiz.Views.Input({ model:model });
9
			this.$el.append( input.render().el );
10
		}
11
	});

Un único campo de entrada

Esta vista siguiente representa un único modelo. En aras de mostrar los tipos de cosas que puedes hacer al codificar JavaScript de esta manera, he tratado de proporcionar algunas técnicas de interacción diferentes y mostrar cómo reaccionar a ellas con Backbone.

Ten en cuenta que aquí estamos especificando un 'tagName' junto con una plantilla. En nuestro caso, esto va a agarrar esa plantilla que vimos anteriormente, analizarla usando datos del modelo, y luego envolver todo en una etiqueta p (lo que nos dará un buen margen alrededor de cada uno).

Observa también cómo se enlazan los eventos a los elementos dentro de una vista. Mucho más limpio que tu devolución de llamada jQuery promedio y lo que es aún mejor es la capacidad de usar un selector jQuery como this.$('input') dentro de nuestras vistas sabiendo que están automáticamente delimitado dentro de la vista. Esto significa que jQuery no está mirando todo el DOM al intentar hacer coincidir un selector.

En esta vista, podremos:

  1. Saber cuándo se ha cambiado un campo de entrada
  2. Actualizar el modelo asociado a él automáticamente (que se utilizará para actualizar automáticamente el campo de selección debajo de él)
  3. Activar el botón Guardar al lado del campo de entrada que ha sido cambiado
  4. Realizar un nuevo guardado en la base de datos
1
/* js/admin.js */
2
3
	Quiz.Views.Input = Backbone.View.extend({
4
		tagName: 'p',
5
		// Get the template from the DOM

6
		template :_.template( $(wpq.inputTempl).html() ),
7
8
		// When a model is saved, return the button to the disabled state

9
		initialize:function () {
10
			var _this = this;
11
			this.model.on( 'sync', function() {
12
				_this.$('button').text( 'Save' ).attr( 'disabled', true );
13
			});
14
		},
15
16
		// Attach events

17
		events : {
18
			'keyup input' : 'blur',
19
			'blur input' : 'blur',
20
			'click button' : 'save'
21
		},
22
23
		// Perform the Save

24
		save : function( e ) {
25
			e.preventDefault();
26
			$(e.target).text( 'wait' );
27
			this.model.save();
28
		},
29
30
		// Update the model attributes with data from the input field

31
		blur : function() {
32
			var input = this.$('input').val();
33
			if ( input !== this.model.get( 'answer' ) ) {
34
				this.model.set('answer', input);
35
				this.$('button').attr( 'disabled', false );
36
			}
37
		},
38
39
		// Render the single input - include an index.

40
		render:function () {
41
			this.model.set( 'index', this.model.collection.indexOf( this.model ) + 1 );
42
			this.$el.html( this.template( this.model.toJSON() ) );
43
			return this;
44
		}
45
	});

El elemento Select

Este elemento select es donde el usuario puede elegir la respuesta correcta. Cuando esta vista es instanciada, recibirá la misma colección de modelos que el contenedor del campo de entrada. Esto será útil más adelante porque podremos escuchar los cambios en el modelo en los campos de entrada y actualizar automáticamente los valores correspondientes dentro de este elemento select.

1
/* js/admin.js */
2
3
	Quiz.Views.Select = Backbone.View.extend({
4
		initialize:function () {
5
			this.collection.each( this.addOption, this );
6
		},
7
		addOption:function ( model ) {
8
			var option = new Quiz.Views.Option({ model:model });
9
			this.$el.append( option.render().el );
10
		}
11
	});

Una visualización de opción única

Nuestra vista final creará un elemento de opción para cada modelo y se añadirá al elemento select anterior. Esta vez he mostrado cómo puedes establecer dinámicamente atributos en el elemento devolviendo un hash de una función de devolución de llamada asignada a la propiedad attributes. Ten en cuenta también que en el método initialize() hemos 'suscrito' para cambiar eventos en el modelo (específicamente, el atributo de answer). Esto básicamente significa simplemente que: cada vez que se cambia el atributo de respuesta de este modelo, se llama al método render() (que en este caso, solo actualizará el texto). Este concepto de "suscribir" o "escuchar" los eventos que se producen dentro de un modelo es realmente lo que hace que Backbone.js y muchas otras bibliotecas similares sean tan poderosas, útiles y sea también un placer trabajar con ellas.

1
/* js/admin.js */
2
3
	Quiz.Views.Option = Backbone.View.extend({
4
		tagName:'option',
5
6
		// returning a hash allows us to set attributes dynamically

7
		attributes:function () {
8
			return {
9
				'value':this.model.get( 'answer_id' ),
10
				'selected':this.model.get( 'correct' )
11
			}
12
		},
13
14
		// Watch for changes to each model (that happen in the input fields and re-render when there is a change

15
		initialize:function () {
16
			this.model.on( 'change:answer', this.render, this );
17
		},
18
		render:function () {
19
			this.$el.text( this.model.get( 'answer' ) );
20
			return this;
21
		}
22
	});

Creación de instancias de colecciones y vistas

Ahora estamos muy cerca, todo lo que tenemos que hacer es crear una instancia de una nueva colección y pasar el JSON que necesita, a continuación, crear una instancia de las vistas 'envoltorio' para el elemento select y para los campos de entrada. Ten en cuenta que también pasamos la propiedad el a nuestras vistas. Estas son referencias al elemento div y select que dejamos en blanco anteriormente en la caja meta.

1
/* js/admin.js */
2
3
	var answers = new Quiz.Collection( wpq.answers );
4
	var selectElem = new Quiz.Views.Select({ collection:answers, el :wpq.answerSelect });
5
	var inputs = new Quiz.Views.Inputs({ collection:answers, el:wpq.answerInput });

3. Activar el plugin

Si has logrado llegar al final, ahora deberías tener un ejemplo completamente funcional de cómo incorporar Backbone JS en un plugin de WordPress. Si sigues adelante y echas un vistazo a los archivos de origen, notarás que la cantidad real de código necesario para incorporar Backbone es relativamente pequeña. Gran parte del código que hemos usado aquí era el PHP necesario para el plugin. Trabajar con Backbone a diario durante las últimas 6 semanas realmente me ha hecho respetar un nuevo descubrimiento en relación a la organización de código front-end y espero que puedas apreciar los beneficios que seguramente proporciona trabajar de esta manera.

Dentro de la comunidad de WordPress puedo imaginar algunos de los plugins más complejos y de alta calidad que realmente se benefician del uso de Backbone y me siento honrado de haber sido capaz de compartir con vosotros una técnica para hacer exactamente eso.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.