Las mejores prácticas para el desarrollo de plugins en cuanto a seguridad, organización de código. Arquitectura de un plugin vista a través de un ejemplo. Herramientas útiles para crear un plugin de WordPress desde cero.
1. Crear un WordPress Plugin desde Cero
Eduardo Turiño
Programador Web
en Bilbao
@etmsoft
linkedin.com/in/eduardoturino
2. ¿Qué veremos? @etmsoft - #WPBilbao
- Conceptos básicos
- Buenas prácticas en el desarrollo de plugins
- Archivos y formato necesarios
- Bloque de definición del plugin.
Atributos.
- readme.txt
- screenshots.png
- Plugin “Share-now” versión no OOP
- Plugin “Share-now” versión OOP
- Subir plugin al repositorio de wordpress.org
Requisitos
- Conocimientos medios en
- PHP
- OOP
- HTML
- CSS
- Javascript / jQuery / Ajax
- Ganas de aportar
- De vez en cuando un Tweet con el
hashtag #WPBilbao
4. @etmsoft - #WPBilbao
Hooks - Acciones
<?php
// Añade código adicional al comportamiento habitual de WordPress
add_action('action_name', 'callback_function ');
add_action( 'save_post', 'notificar_guardado', 10, 2 );
function notificar_guardado( $post_id, $post ) {
// Notificar por email que se ha guardado el post
wp_mail('admin@dominio.com ', 'Se ha guardado el post' . $post_id);
}
add_action( 'wp_head', 'hacer_web_responsive' );
function hacer_web_responsive() {
echo '<meta name="viewport" content="initial-scale=1.0,
user-scalable=no" />';
}
?>
5. @etmsoft - #WPBilbao
Hooks - Filtros
<?php
// Cambia el valor de los datos antes de mostrarlos o guardarlos en BD
add_filter('filter_name', 'callback_function ');
add_filter( 'body_class', 'add_slug_body_class' );
function add_slug_body_class( $classes ) {
global $post;
if ((is_single() || is_page()) && isset( $post ) ) {
$classes[] = $post->post_type . '-' . $post->post_name;
}
return $classes;
}
?>
// Genera: <body class="page page-contacto">
6. <?php
/*
Plugin Name: CTA Compartir
Plugin URI: http://wpbilbao.es
Description: Añade un texto de llamada a la acción para compartir o
comentar una entrada.
Version: 0.1
Author: Eduardo Turiño
Author URI: http://etmsoft.com
*/
add_filter( 'the_content', 'cta_compartir' );
function cta_compartir( $content ) {
$cta_compartir = '<p>Si te ha gustado este artículo comentanos que te ha
parecido o compártelo en las redes sociales</p>';
$content = apply_filters('the_content', $content) . $cta_compartir;
return $content;
}
?>
@etmsoft - #WPBilbao
Hooks - Ejemplo de plugin con filtro
9. @etmsoft - #WPBilbao
Conceptos básicos - Cabecera completa
<?php
/*
Plugin Name: Mi Plugin
Plugin URI: http://etmsoft.com/plugins/mi-plugin (Puede estar en WordPress.org o tu sitio)
Description: Aquí va la descripción breve del plugin (no más de 140 caracteres)
Version: 1.5
Author: Eduardo Turiño (pueden haber varios autores)
Author URI: http://etmsoft.com
License: GPL2
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Domain Path: /languages
Text Domain: mi-plugin
// Recomendado incluir descripción de la licencia:
{Plugin Name} is free software: you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation, either version 2 of the
License, or any later version.
{Plugin Name} is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with {Plugin Name}. If
not, see {License URI}.
*/
10. @etmsoft - #WPBilbao
Conceptos básicos - readme.txt
=== Share Now ===
Contributors: (Debe ser una lista de Id de usuarios de wordpress.org)
Donate link: http://etmsoft.com/
Tags: share, social buttons
Requires at least: 3.0.1
Tested up to: 4.4
Stable tag: 4.3
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Aquí una breve descripción del plugin. Esto no debería ser más de 150 caracteres. Sin
etiquetado.
== Descripción ==
Esta es la descripción larga. No hay límite, y se puede utilizar etiquetado (también en las
secciones siguientes). Por compatibilidad con versiones anteriores, si esta sección no se
indica, toda la descripción corta será mostrada y el etiquetado será válido.
== Instalación ==
Esta sección describe cómo instalar el plugin y los pasos para hacerlo funcionar.
1. Paso 1
1. Paso 2
11. @etmsoft - #WPBilbao
Conceptos básicos - Licencia GPLv2
You must cause any work that you distribute or publish, that in whole or in part contains or is
derived from the Program or any part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
Eres libre de modificar, reutilizar todo o parte del código de un plugin o tema para tus propios
proyectos, incluso si a ese proyecto le sacas rendimiento económico.
If the program dynamically links plug-ins, and they make function calls to each other and share data
structures, we believe they form a single program, which must be treated as an extension of both
the main program and the plug-ins. This means the plug-ins must be released under the GPL....
Sólo por el hecho de que un plugin o tema utilice funciones de WordPress, ya se adhiere a la licencia
GPL, porque será tratado como una extensión del software base, que es el WordPress, que está bajo
dicha licencia.
Por tanto, aunque sea un Plugin / Tema comprado:
- Puedes eliminar enlaces de referencias al autor.
- No se pueden combinar licencias Creative Commons + GPL
- Puedes instalarlo varias veces
12. @etmsoft - #WPBilbao
Conceptos básicos - Activación / Desactivación
<?php
/*
Plugin Name: Mi Plugin
...
*/
register_activation_hook( __FILE__, 'miplugin_activacion' );
function miplugin_activacion() {
// Acciones a realizar durante la activación
// ...
}
register_deactivation_hook( __FILE__, 'miplugin_desactivacion' );
function miplugin_desactivacion() {
// Borrar los permalinks
flush_rewrite_rules();
}
?>
13. @etmsoft - #WPBilbao
Conceptos básicos - Desinstalación. 2 Opciones
<?php
/*
Plugin Name: Mi Plugin
*/
register_uninstall_hook( __FILE__, 'miplugin_desinstalar' );
?>
uninstall.php
<?php
// Si uninstall.php no es llamado
// desde WordPress, salir
if ( !defined( 'WP_UNINSTALL_PLUGIN' ) ) {
exit();
}
delete_option( 'miplugin_opciones' );
// Para opciones en un WordPress Multisite
delete_site_option( 'miplugin_opciones' );
// Eliminar tabla de la base de datos
global $wpdb;
$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}miplugin" );
?>
14. @etmsoft - #WPBilbao
Conceptos básicos - Desactivación vs Desinstalación
Escenario Hook de Desactivación ‘Hook’ de Desinstalación
Eliminar opciones del
plugin
No Sí
Limpiar caché de objetos
generados por el plugin
Sí No
16. @etmsoft - #WPBilbao
Mejores Prácticas - Prefijos, Condicionales y Carpetas
<?php
if ( !function_exists('miplugin_init' ) ) {
function miplugin_init() {
register_setting( ' miplugin_setting_example', 'foo' );
register_setting( ' miplugin_setting_demo', 'bar' );
}
}
if ( is_admin() ) {
// Estamos en modo admin (en el backend)
require_once( dirname(__file__).'/admin/myplugin_admin.php' );
}
?>
/mi-plugin
mi-plugin.php /images
uninstall.php
/assets /includes
/admin /settings
/js
/css
17. @etmsoft - #WPBilbao
Mejores Prácticas - Arquitectura
Enfoques
1. Un único archivo de plugin, con funciones. Hello Dolly
2. Un único archivo con una clase y métodos. ej. Update from Bottom
3. Un archivo principal de plugin y varios archivos con clases, cada una realizando su función.
Implementación de patrones OOP y organización de código
Ian Dunn de Automattic - Arquitectura MVC en Plugins
22. @etmsoft - #WPBilbao
Seguridad - Roles y Capabilities de usuarios
<?php
http://misitio.com/noticias?accion=eliminar&id_noticia=5
if ( isset($_REQUEST['accion']) && $_REQUEST['accion']=='eliminar' ) {
add_action('init', 'miplugin_borrar_noticia');
}
function miplugin_borrar_noticia() {
if ( ! current_user_can( 'edit_others_posts' ) )
return;
// Obtener el ID de la noticia.
$id_noticia = (isset($_REQUEST['id_noticia'])?get_post((int)$_REQUEST
['id_noticia']):false;
// No es un post? Sintiéndolo mucho..
if ( empty($id_noticia) )
return;
// Borrar noticia
wp_trash_post( $id_noticia );
}
?>
23. @etmsoft - #WPBilbao
Seguridad - Validación de datos
Niveles de validación:
1. Javascript
a. Campos requeridos dejados en blanco.
b. Formatos de número (teléfonos, código postal, etc.)
c. Campos de cantidad > 0
2. Funciones PHP
a. isset() y empty(): la variable existe y no está en blanco.
b. mb_strlen() o strlen(): longitud de caracteres.
c. preg_match(), strpos() : buscar ocurrencias de una cadena dentro de otra.
d. count(): elementos de un array()
e. in_array(): chequea si un elemento existe en un array()
3. Funciones WordPress
a. is_email(): chequea si un email es válido.
b. term_exists(): chequea si una etiqueta, categoría o taxonomía existe.
c. username_exists() : chequea si un usuario existe.
d. wp_validate_auth_cookie() : valida la cookie de autenticación.
e. Familia de funciones *_exists(), *_validate(), is_*()
24. @etmsoft - #WPBilbao
Seguridad - Sanitización
Funciones de sanitización
● Chequea código UTF-8 no válido.
● Convierte el ‘<’ en una entidad <
● Elimina etiquetado HTML
● Eliminar cambios de línea, tabulaciones y espacios en blanco
extras
● Eliminar octetos ( 0x6F7395 )
<input id="title" type="text" name="title" />
<?php
$title = sanitize_text_field( $_POST['title'] );
update_post_meta( $post->ID, 'title', $title );
?>
sanitize_email()
sanitize_file_name()
sanitize_html_class()
sanitize_key()
sanitize_meta()
sanitize_mime_type()
sanitize_option()
sanitize_sql_orderby()
sanitize_text_field()
sanitize_title()
sanitize_title_for_query()
sanitize_title_with_dashes(
)
sanitize_user()
esc_url_raw()
wp_filter_post_kses()
wp_filter_nohtml_kses()
26. @etmsoft - #WPBilbao
Seguridad - Nonces (Number + Once)
HTML
// Número de un sólo uso
<form method="post">
<!-- some inputs here ... -->
<?php wp_nonce_field( 'accion_del_formulario', 'campo_verificacion' ); ?>
</form>
<?php
if ( ! isset( $_POST['campo_verificacion'] ) ||
! wp_verify_nonce( $_POST['campo_verificacion'], 'accion_del_formulario' )
) {
print 'Lo sentimos, el formulario no ha sido verificado.';
exit;
} else {
// Procesar los datos de formulario
}
?>
46. Publicar Plugins - Requisitos @etmsoft - #WPBilbao
1. Licencia: GPLv2
2. Usar Subversion
3. readme.txt
4. No “trialware” (plugins que dejan de funcionar pasado
un tiempo)
5. No “serviceware” (plugins que hacen referencia a SaaS,
servicios en la nube)
6. …wordpress.org/plugins/about/guidelines/
47. Publicar Plugins - Pasos @etmsoft - #WPBilbao
1. Solicitud: wordpress.org/plugins/add/
2. Una vez aceptado: plugins.svn.wordpress.org/mi-plugin/
a. Cliente subversion, ej. Tortoise.
b. Hacer ‘checkout’ en una subcarpeta ej. _wordpressorg
/mi-plugin
/_wordpressorg
/tags
/assets
/trunk
1.0 después del checkout
1.5
2.0
/branches
/admin
/js
/css
/images
/includes
/settings
mi-plugin.php
tortoisesvn.net
48. Publicar plugin en el repositorio. @etmsoft - #WPBilbao
1.- Checkout
2.- Copiar plugin en trunk
3.- Commit (upload)
49. @etmsoft - #WPBilbaoPublicar plugin en el repositorio.
<?php
/*
Plugin Name: Mi Plugin
Plugin URI: http://etmsoft.com/plugins/mi-plugin (Puede estar en WordPress.org o tu sitio)
Description: Aquí va la descripción breve del plugin (no más de 140 caracteres)
Version: 1.5
Author: Eduardo Turiño (pueden haber varios autores)
Author URI: http://etmsoft.com
License: GPL2
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Domain Path: /languages
Text Domain: mi-plugin
?>
readme.txt
=== Share Now === == Changelog ==
Contributors: (Lista de Id de usuarios de wordpress.org) = 1.0 =
Donate link: http://etmsoft.com/ * Primera versión.
Tags: share, social buttons * Otro cambio.
Requires at least: 3.0.1 = 1.5 =
Tested up to: 4.4 * Siguiente versión
Stable tag: 1.5 * Otro cambio
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html