Advertisement
  1. Code
  2. Creative Coding

Desarrollo de plugins con WordPress Boilerplates: Construyendo un plugin

Scroll to top
Read Time: 17 min
This post is part of a series called Developing Plugins With WordPress Boilerplates.
Developing Plugins With WordPress Boilerplates: Why Boilerplates Matter

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

En el primer artículo de esta serie, analizamos cómo una base reutilizable o "boilerplate" puede mejorar tus esfuerzos de desarrollo proporcionandote una base a partir de la cual puedes construir tu proyecto.

Idealmente, los boilerplates deben proporcionar un marco suficiente para empezar, al mismo tiempo que te permiten centrarte en la lógica específica del negocio, la necesidad principal o el código del ámbito concreto que necesitas escribir.

Específicamente, echamos un vistazo a WordPress Widget Boilerplates y a WordPress Plugin Boilerplate. En este artículo, vamos a aprovechar Plugin Boilerplate para escribir nuestro propio plugin con el fin de ver cómo los boilerplates sientan las bases para escribir un buen código, y cómo podemos usarlos como punto de partida para nuestro futuro trabajo.


Un plugin de mensaje de entrada

En este artículo, vamos a crear un widget de notificación de entrada que permite al autor añadir un nuevo mensaje de entrada antes del contenido en tu página. Esto estará basado en un plugin que ya existe por ahí para que puedas tener un punto de referencia una vez que el proyecto se haya completado.

Al igual que con el resto de mis tutoriales, me gusta planificar el proyecto con antelación, así que vamos a establecer todo lo que haremos:

  1. Descargar una copia de WordPress Plugin Boilerplate
  2. Cumplimentar todos los requisitos con la información específica para tu propio proyecto
  3. Implementar el código necesario para mostrar y guardar información en una caja meta de una entrada
  4. Comprobar la existencia de post meta y luego renderizarlo en el contenido
  5. Finalizar el README y la localización

En general, es un plugin relativamente simple, pero debería proporcionar un sólido ejemplo de cómo Boilerplates te permite centrarte en tu funcionalidad concreta todo el tiempo mientras trabajas dentro del contexto de las mejores prácticas de WordPress.


Construyendo el widget

1. Descarga WordPress Plugin Boilerplate

Para empezar, necesitas descargar una copia de WordPress Plugin Boilerplate. Puedes hacerlo navegando a su página de GitHub, haciendo luego clic en el botón 'zip' situado cerca de la parte superior de la página o haciendo clic aquí.

A continuación, extrae el contenido de la descarga en tu directorio de plugins. Inicialmente deberías crear un directorio llamado plugin-boilerplate.

WordPress Plugin BoilerplateWordPress Plugin BoilerplateWordPress Plugin Boilerplate Cambia el nombre a post-message. En este punto, estamos listos para comenzar a trabajar en el código fuente para el boilerplate.

2. Cumplimenta los requisitos en el boilerplate

A continuación, abre el directorio post-message en tu IDE favorito. Lo primero que queremos hacer es abrir plugin.php y luego localizar todos los requisitos que existen en el código.

De forma predeterminada, el código tendrá un aspecto parecido a este:

1
<?php
2
/*

3
Plugin Name: TODO

4
Plugin URI: TODO

5
Description: TODO

6
Version: 1.0

7
Author: TODO

8
Author URI: TODO

9
Author Email: TODO

10
License:

11


12
  Copyright 2013 TODO (email@domain.com)

13


14
  This program is free software; you can redistribute it and/or modify

15
  it under the terms of the GNU General Public License, version 2, as

16
  published by the Free Software Foundation.

17


18
  This program is distributed in the hope that it will be useful,

19
  but WITHOUT ANY WARRANTY; without even the implied warranty of

20
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

21
  GNU General Public License for more details.

22


23
  You should have received a copy of the GNU General Public License

24
  along with this program; if not, write to the Free Software

25
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

26


27
*/
28
29
// TODO: rename this class to a proper name for your plugin

30
class PluginName {
31
32
	/*--------------------------------------------*

33
	 * Constructor

34
	 *--------------------------------------------*/
35
36
	/**

37
	 * Initializes the plugin by setting localization, filters, and administration functions.

38
	 */
39
	function __construct() {
40
41
		// Load plugin text domain

42
		add_action( 'init', array( $this, 'plugin_textdomain' ) );
43
44
		// Register admin styles and scripts

45
		add_action( 'admin_print_styles', array( $this, 'register_admin_styles' ) );
46
		add_action( 'admin_enqueue_scripts', array( $this, 'register_admin_scripts' ) );
47
48
		// Register site styles and scripts

49
		add_action( 'wp_enqueue_scripts', array( $this, 'register_plugin_styles' ) );
50
		add_action( 'wp_enqueue_scripts', array( $this, 'register_plugin_scripts' ) );
51
52
		// Register hooks that are fired when the plugin is activated, deactivated, and uninstalled, respectively.

53
		register_activation_hook( __FILE__, array( $this, 'activate' ) );
54
		register_deactivation_hook( __FILE__, array( $this, 'deactivate' ) );
55
		register_uninstall_hook( __FILE__, array( $this, 'uninstall' ) );
56
57
	    /*

58
	     * TODO:

59
	     * Define the custom functionality for your plugin. The first parameter of the

60
	     * add_action/add_filter calls are the hooks into which your code should fire.

61
	     *

62
	     * The second parameter is the function name located within this class. See the stubs

63
	     * later in the file.

64
	     *

65
	     * For more information:

66
	     * http://codex.wordpress.org/Plugin_API#Hooks.2C_Actions_and_Filters

67
	     */
68
	    add_action( 'TODO', array( $this, 'action_method_name' ) );
69
	    add_filter( 'TODO', array( $this, 'filter_method_name' ) );
70
71
	} // end constructor

72
73
	/**

74
	 * Fired when the plugin is activated.

75
	 *

76
	 * @param	boolean	$network_wide	True if WPMU superadmin uses "Network Activate" action, false if WPMU is disabled or plugin is activated on an individual blog

77
	 */
78
	public function activate( $network_wide ) {
79
		// TODO:	Define activation functionality here

80
	} // end activate

81
82
	/**

83
	 * Fired when the plugin is deactivated.

84
	 *

85
	 * @param	boolean	$network_wide	True if WPMU superadmin uses "Network Activate" action, false if WPMU is disabled or plugin is activated on an individual blog

86
	 */
87
	public function deactivate( $network_wide ) {
88
		// TODO:	Define deactivation functionality here

89
	} // end deactivate

90
91
	/**

92
	 * Fired when the plugin is uninstalled.

93
	 *

94
	 * @param	boolean	$network_wide	True if WPMU superadmin uses "Network Activate" action, false if WPMU is disabled or plugin is activated on an individual blog

95
	 */
96
	public function uninstall( $network_wide ) {
97
		// TODO:	Define uninstall functionality here

98
	} // end uninstall

99
100
	/**

101
	 * Loads the plugin text domain for translation

102
	 */
103
	public function plugin_textdomain() {
104
105
		// TODO: replace "plugin-name-locale" with a unique value for your plugin

106
		load_plugin_textdomain( 'plugin-name-locale', false, dirname( plugin_basename( __FILE__ ) ) . '/lang' );
107
108
	} // end plugin_textdomain

109
110
	/**

111
	 * Registers and enqueues admin-specific styles.

112
	 */
113
	public function register_admin_styles() {
114
115
		// TODO:	Change 'plugin-name' to the name of your plugin

116
		wp_enqueue_style( 'plugin-name-admin-styles', plugins_url( 'plugin-name/css/admin.css' ) );
117
118
	} // end register_admin_styles

119
120
	/**

121
	 * Registers and enqueues admin-specific JavaScript.

122
	 */
123
	public function register_admin_scripts() {
124
125
		// TODO:	Change 'plugin-name' to the name of your plugin

126
		wp_enqueue_script( 'plugin-name-admin-script', plugins_url( 'plugin-name/js/admin.js' ) );
127
128
	} // end register_admin_scripts

129
130
	/**

131
	 * Registers and enqueues plugin-specific styles.

132
	 */
133
	public function register_plugin_styles() {
134
135
		// TODO:	Change 'plugin-name' to the name of your plugin

136
		wp_enqueue_style( 'plugin-name-plugin-styles', plugins_url( 'plugin-name/css/display.css' ) );
137
138
	} // end register_plugin_styles

139
140
	/**

141
	 * Registers and enqueues plugin-specific scripts.

142
	 */
143
	public function register_plugin_scripts() {
144
145
		// TODO:	Change 'plugin-name' to the name of your plugin

146
		wp_enqueue_script( 'plugin-name-plugin-script', plugins_url( 'plugin-name/js/display.js' ) );
147
148
	} // end register_plugin_scripts

149
150
	/*--------------------------------------------*

151
	 * Core Functions

152
	 *---------------------------------------------*/
153
154
	/**

155
 	 * NOTE:  Actions are points in the execution of a page or process

156
	 *        lifecycle that WordPress fires.

157
	 *

158
	 *		  WordPress Actions: http://codex.wordpress.org/Plugin_API#Actions

159
	 *		  Action Reference:  http://codex.wordpress.org/Plugin_API/Action_Reference

160
	 *

161
	 */
162
	function action_method_name() {
163
    	// TODO:	Define your action method here

164
	} // end action_method_name

165
166
	/**

167
	 * NOTE:  Filters are points of execution in which WordPress modifies data

168
	 *        before saving it or sending it to the browser.

169
	 *

170
	 *		  WordPress Filters: http://codex.wordpress.org/Plugin_API#Filters

171
	 *		  Filter Reference:  http://codex.wordpress.org/Plugin_API/Filter_Reference

172
	 *

173
	 */
174
	function filter_method_name() {
175
	    // TODO:	Define your filter method here

176
	} // end filter_method_name

177
178
} // end class

179
180
// TODO:	Update the instantiation call of your plugin to the name given at the class definition

181
$plugin_name = new PluginName();

A continuación, tenemos que hacer cada requisito específico del plugin para que coloquemos todas las instancias donde sea necesario con una variación del nombre del plugin.

Por ejemplo:

  • Reemplaza el nombre del plugin por Post Message
  • Reemplaza la URL del plugin por la URL de tu elección
  • Rellena el nombre, la dirección de correo electrónico y toda la información personal con lo que corresponda
  • Asigna un nombre a la clase Post_Message
  • Asigna un nombre a las cadenas, los nombres de clase y los IDs de post-message relacionados con la configuración regional

A continuación, también podemos eliminar todas las llamadas a JavaScript y a hojas de estilos, excepto los estilos admin.css. Usaremos este archivo más tarde. También asegúrate de eliminar los siguientes archivos del Boilerplate:

  • views/display.php
  • css/plugin.css
  • js/admin.js
  • js/plugin.js

Esto debería dejarte con la siguiente estructura de directorios:

WordPress Plugin Boilerplate Directory StructureWordPress Plugin Boilerplate Directory StructureWordPress Plugin Boilerplate Directory Structure

Ten en cuenta que esto es habitual en un Boilerplate: en cualquier caso, deberías querer quitar algo de él. Si tienes que añadirle algo que te ayude a despegar del suelo, o que sea más fundamental, en ese caso podría ser una oportunidad para mejorarlo.

De todos modos, aunque aún no hemos terminado, y aunque vamos a añadir cosas al plugin, el archivo debería tener un aspecto similar a esto en este momento:

1
<?php
2
/*

3
Plugin Name: Tom McFarlin

4
Plugin URI: http://tommcfarlin.com/single-post-message/

5
Description: A simple way to add a message at the top of each of your posts.

6
Version: 1.0

7
Author: Tom McFarlin

8
Author URI: http://tommcfarlin.com/

9
Author Email: tom@tommcfarlin.com

10
License:

11


12
  Copyright 2013 Tom McFarlin (om@tommcfarlin.com)

13


14
  This program is free software; you can redistribute it and/or modify

15
  it under the terms of the GNU General Public License, version 2, as

16
  published by the Free Software Foundation.

17


18
  This program is distributed in the hope that it will be useful,

19
  but WITHOUT ANY WARRANTY; without even the implied warranty of

20
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

21
  GNU General Public License for more details.

22


23
  You should have received a copy of the GNU General Public License

24
  along with this program; if not, write to the Free Software

25
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

26


27
*/
28
29
class Post_Message {
30
31
	/*--------------------------------------------*

32
	 * Constructor

33
	 *--------------------------------------------*/
34
35
	/**

36
	 * Initializes the plugin by setting localization, filters, and administration functions.

37
	 */
38
	function __construct() {
39
40
		// Load plugin text domain

41
		add_action( 'init', array( $this, 'plugin_textdomain' ) );
42
43
		// Register admin styles and scripts

44
		add_action( 'admin_print_styles', array( $this, 'register_admin_styles' ) );
45
46
	} // end constructor

47
48
	/**

49
	 * Loads the plugin text domain for translation

50
	 */
51
	public function plugin_textdomain() {
52
		load_plugin_textdomain( 'post-message', false, dirname( plugin_basename( __FILE__ ) ) . '/lang' );
53
	} // end plugin_textdomain

54
55
	/**

56
	 * Registers and enqueues admin-specific styles.

57
	 */
58
	public function register_admin_styles() {
59
		wp_enqueue_style( 'post-message-admin', plugins_url( 'post-message/css/admin.css' ) );
60
	} // end register_admin_styles

61
62
} // end class

63
64
new Post_Message();

A continuación, tenemos que empezar a trabajar en la lógica de nuestro negocio principal.

3. Implementar el código necesario para mostrar y guardar información en una caja meta de un post

En primer lugar, tenemos que identificar exactamente cómo va a funcionar esto:

  1. Mostraremos una caja meta de post directamente bajo el editor de contenido
  2. Incluirá un área de texto que permite a los usuarios proporcionar su propio contenido
  3. Cuando se actualiza el post, debe guardar el contenido del área de texto

Así que lo primero que tenemos que hacer es introducir un gancho y una función con el fin de capturar los datos que contiene la caja meta. En el constructor, vamos a añadir la siguiente línea:

add_action( 'add_meta_boxes', array( $this, 'add_notice_metabox' ) );

A continuación, necesitamos definir la función add_notice_metabox para que podamos representar realmente el cuadro meta, así que vamos a proporcionar ahora esa función:

1
function add_notice_metabox() {
2
3
	add_meta_box(
4
		'post_message',
5
		__( 'Post Message', 'post-message' ),
6
		array( $this, 'post_message_display' ),
7
		'post',
8
		'normal',
9
		'high'
10
	);
11
12
} // end add_notice_metabox

Después de eso, necesitamos escribir una función que sea responsable de representar realmente el contenido del post:

1
function post_message_display( $post ) {
2
3
	wp_nonce_field( plugin_basename( __FILE__ ), 'post_message_nonce' );
4
5
	// The textfield and preview area

6
	echo '<textarea id="post-message" name="post_message" placeholder="' . __( 'Enter your post message here. HTML accepted.', 'post-message' ) . '">' . esc_textarea( get_post_meta( $post->ID, 'post_message', true ) ) . '</textarea>';
7
8
} // end post_message_display

Arriba, observa que hemos introducido un campo nonce por motivos de seguridad. Observa también que hemos dado a esta área de texto (textarea) el ID post-message para que podamos darle fácilmente estilo usando CSS, y le hemos dado el nombre post_message que será útil a medida que guardemos el contenido del textarea en los metadatos del post concreto.

Por último, hemos aprovechado la función esc_textarea para asegurarnos de que estamos codificando correctamente nuestros datos a fin de representarlos en el área de texto.

En este punto, vamos a añadir un poco de estilo utilizando el archivo admin.css para dar al mensaje del post un aspecto ligeramente diferente al contenido:

1
#post-message { width: 100%; }

Esto debería dar lugar a algo como lo siguiente:

Plugin Message ExamplePlugin Message ExamplePlugin Message Example

Por supuesto, aún no hemos terminado. Necesitamos guardar y recuperar los datos cuando el usuario haga clic en el botón "Publicar" o "Actualizar". Para ello, necesitamos configurar una devolución de llamada que guarde los datos del post.

Así que lo último que tenemos que hacer es introducir una función save_notice. En primer lugar, registraremos esto en el constructor con el siguiente código:

add_action( 'save_post', array( $this, 'save_notice' ) );

A continuación, definiremos la siguiente función:

1
function save_notice( $post_id ) {
2
3
	if ( isset( $_POST['post_message_nonce'] ) && isset( $_POST['post_type'] ) ) {
4
5
		// Don't save if the user hasn't submitted the changes

6
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
7
			return;
8
		} // end if

9
10
		// Verify that the input is coming from the proper form

11
		if ( ! wp_verify_nonce( $_POST['post_message_nonce'], plugin_basename( __FILE__ ) ) ) {
12
			return;
13
		} // end if

14
15
		// Make sure the user has permissions to post

16
		if ( 'post' == $_POST['post_type'] ) {
17
			if ( ! current_user_can( 'edit_post', $post_id ) ) {
18
				return;
19
			} // end if

20
		} // end if/else

21
22
		// Read the post message

23
		$post_message = isset( $_POST['post_message'] ) ? $_POST['post_message'] : '';
24
25
		// If the value for the post message exists, delete it first. Don't want to write extra rows into the table.

26
		if ( 0 == count( get_post_meta( $post_id, 'post_message' ) ) ) {
27
			delete_post_meta( $post_id, 'post_message' );
28
		} // end if

29
30
		// Update it for this post.

31
		update_post_meta( $post_id, 'post_message', $post_message );
32
33
	} // end if

34
35
} // end save_notice

Hemos explicado cómo guardar el contenido de los metadatos del post en profundidad en artículos anteriores, así que no quiero repetir este punto aquí, basta con decir que la función hace lo siguiente:

  • Comprueba que el usuario tiene permiso para guardar esta información
  • Elimina cualquier metadato existentes en el post
  • Guarda los datos en los metadatos del post asociados

En este punto, estamos listos para probar el plugin, así que rellena el textarea, guarda los datos y, cuando la página se actualice, asegúrate de que los datos también se muestran en el textarea.

Si es así, estamos listos para continuar; de lo contrario, asegúrate de que el código se parezca al código de más arriba.

4. Renderizar el aviso del post

A continuación, estamos listos para representar el mensaje del post en el contenido. El proceso para hacer esto será el siguiente:

  • Registrar una función con el filtro the_content
  • Comprobar la existencia de metadatos de post
  • En el caso de que existan, renderizarlos por encima del contenido

Así que vamos a hacer precisamente eso. En primer lugar, vamos a registrar una función con el filtro the_content:

add_filter( 'the_content', array( $this, 'prepend_post_message' ) );

Después de eso, vamos a configurar la función real:

1
function prepend_post_message( $content ) {
2
3
	// If there is a notice, prepend it to the content

4
	if ( '' != get_post_meta( get_the_ID(), 'post_message', true ) ) {
5
6
		$post_message = '<p class="post-message">';
7
		$post_message .= get_post_meta( get_the_ID(), 'post_message', true );
8
		$post_message .= '</p><!-- /.post-message -->';
9
10
		$content = $post_message . $content;
11
12
	} // end if

13
14
	return $content;
15
16
} // end prepend_post_message

Ten en cuenta que el mensaje del post está contenido dentro de su propio elemento p con su propio nombre de clase para que puedas aplicarle estilo fácilmente según desees, y si lo deseas.

En este punto, debemos tener todo lo que necesitamos para ver el mensaje del post, así que vamos a probarlo. Crea un mensaje de post, publícalo y, a continuación, observa el post en tu navegador.

A continuación, quita el contenido del post y, a continuación, comprueba que no aparezca nada.

Bastante fácil, ¿no?

5. Finalizar el README y la localización

Por último, tenemos que asegurarnos de limpiar el archivo README y localizar correctamente el plugin.

En primer lugar, el archivo README debe contener la información habitual. Esto es en gran parte subjetivo; no obstante, a continuación proporciono un ejemplo de README:

1
=== Post Message ===
2
Contributors: tommcfarlin
3
Donate link: http://tommcfarlin.com/single-post-message/
4
Tags: post
5
Requires at least: 3.4.1
6
Tested up to: 3.5
7
Stable tag: 1.0
8
License: GPLv2 or later
9
License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
11
Easily add short messages and announcements above posts. Displays in the RSS feed and on the blog.
12
13
== Description ==
14
15
Post Message is a plugin that allows you to add custom messages, announcements, and notices to individual posts. It's styled to grab the reader's attention and will render in both the browser *and* in RSS readers.
16
17
Post Message...
18
19
* Supports the use of HTML tags in the message content
20
* Is available directly under the post content editor
21
* Is fully localized and ready for translation
22
23
== Installation ==
24
25
= Using The WordPress Dashboard =
26
27
1. Navigate to the 'Add New' Plugin Dashboard
28
1. Select `post-message.zip` from your computer
29
1. Upload
30
1. Activate the plugin on the WordPress Plugin Dashboard
31
32
= Using FTP =
33
34
1. Extract `post-message.zip` to your computer
35
1. Upload the `post-messsage` directory to your `wp-content/plugins` directory
36
1. Activate the plugin on the WordPress Plugins dashboard
37
38
== Changelog ==
39
40
= 1.0 =
41
* Initial release

Y por último, la localización también debería ser fácil: Simplemente abre el archivo 'plugin.po' en el directorio 'lang' en tu IDE, asegúrate de cambiar el nombre del plugin y la información del autor, luego ábrelo en POEdit para registrar los archivos de localización.

Localizing The PluginLocalizing The PluginLocalizing The Plugin

¡Guarda tu trabajo y listo!


Conclusión

En esta serie, hemos examinado exactamente lo que se necesita para aprovechar WordPress Boilerplates, cómo pueden ayudar e impactar nuestro flujo de trabajo, y nos ayudan a centrarnos más en el núcleo de nuestro proyecto en lugar de reinventar la rueda y levantarse y seguir repitiendo mucho de lo que ya es necesario.

Además, hemos creado un plugin que se puede descargar para su posterior revisión.

Esperemos que esta serie haya proporcionado un ejemplo de por qué debes usar código reutilizable cuando sea aplicable, y haya ayudado a mostrar cómo pueden aliviar la frustración de tener que volver a escribir gran parte del mismo código en cada uno de tus proyectos.

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.