Descargar una lista de Temas en sus últimas versiones

A veces me encuentro que tengo que descargar un montón de Temas para probarlos. Con este simple script (sólo para usuarios Unix/Mac) podrás elegir de dónde descargarlos (el repositorio de wp.org o wp.com) y elegir una lista para bajar. El script descargará la última versión de cada Tema y los dejará en la carpeta desde donde ejecutas el script. No mostrará nada por pantalla a menos de que aparezca un error.

Script en Github.com

Generar dinámicamente CSS: La guía definitiva

Existe una situación muy común cuando desarrollamos un Plugin o Tema: Tenemos una serie de opciones que el usuario puede tocar a su antojo para personalizar una serie de estilos, sean colores, márgenes, fuentes o cualquier otro elemento visual. Sabemos cómo agregar una hoja de estilos en WordPress usando la función wp_enqueue_style pero no podemos generar las reglas dinámicamente, esto es, con PHP dentro de la hoja CSS.

Imaginemos que tenemos unas opciones en nuestra Base de Datos tal que así:

$options = array(
	'background-color' => '#DDD',
	'font-size' => 23
);

¿No sería maravilloso si en nuestra hoja de estilos pudiéramos hacer algo así?

$options = get_option( 'my-options' );
.my-class {
	background-color:<?php echo $options['background-color']; ?>;
	font-size:<?php echo $options['font-size']; ?>px;
}

Obviamente se puede, veamos qué posibilidades tenemos:

La forma brusca: El hook wp_head

No hay en realidad ningún problema en utilizar este hook para añadir algunos estilos:

De esta forma, los estilos quedan encerrados entre nuestras etiquetas <head></head> de nuestra página.

No está mal: Las reglas se generan bien y queda en la cabecera. No obstante, si usamos muchas reglas (por ejemplo, la personalización de un Tema), la cabecera de nuestra página podría quedar demasiado larga, añadiendo carga adicional a nuestra página. Cuando una página HTML llega al usuario, el navegador lee el cuerpo del código HTML mientras carga en paralelo el resto de los elementos como hojas de estilo o ficheros Javascript (no funciona exactamente así pero eso daría para otro post). Lo que nos interesa es que la página cargue lo más rápido posible mientras en paralelo se descargan las hojas de estilo adicionales.

La forma elegante: Hojas de estilo “virtuales”

Con hoja de estilo “virtual” nos referimos a cargar un fichero CSS que no existe. ¿Cómo? Lo vamos a explicar, pero vayamos paso a paso. Primero tenemos que saber cómo va esto del protocolo HTTP (algo básico pero que tendemos a pasarlo por alto).

Cuando nuestro navegador solicita la descarga de una hoja de estilos, pide al servidor mediante un mensaje dicho fichero. El servidor devuelve una respuesta compuesta por una cabecera que contiene los datos identificativos del fichero: longitud en bytes del fichero, tipo de contenido y el tiempo de expiración de la caché entre otros campos. Bajo la cabecera se emite el cuerpo del fichero que contiene pues eso, el contenido del fichero.

Es fácil verlo en Chrome con las herramientas para desarrolladores

headers

En este caso, el fichero noticons.css se descarga de la URL https://s1.wp.com/i/noticons/noticons.css. Nos interesa especialmente la parte de Response Headers. Ésta es la cabecera que el servidor ha devuelto y lo que nos debería llamar más la atención es el campo llamado Content Type que nos dice qué tipo de contenido tiene el fichero, en este caso text/css.

¿Qué pistas nos da todo esto? Bien, si queremos generar dinámicamente nuestro CSS tenemos que tener en cuenta que cuando el navegador solicite nuestro archivo “virtual”, nuestro sitio tiene que devolver una respuesta con una cabecera cuyo campo Content Type sea text/css. Y no hay más. Si el navegador del usuario reconoce dicha URL como un fichero CSS, lo aplicará como tal.

Ahora, sigamos unos pasos básicos que nos lleve a la meta:

  • ¿Qué URL debería tener nuestra hoja de estilos “virtual”? Bueno, la que queramos en realidad. Pongamos un ejemplo: https://holadolly.wordpress.com?dolly-styles=true. Esa URL, que normalmente devolvería un fichero HTML vamos a “engañarla” para que devuelva un fichero CSS en su lugar. En WordPress podemos generar dicha URL fácilmente:
$css_url = add_query_arg( 'dolly-styles', 'true', home_url() );
  • Agregar dicha URL como si fuera un estilo normal usando la función wp_enqueue_style

  • Hasta aquí, más o menos todo bien pero la URL todavía no devuelve un CSS, de hecho devuelve la página HTML de la home de nuestro sitio. Ahora llega el momento del engaño. Cuando llamamos a esa URL, WordPress se carga de forma normal pero hay que saber que no necesitamos cargarlo al completo. La idea es comprobar que existe una variable $_GET llamada ‘dolly-styles’, que tiene valor ‘true’. Si esta condición se cumple le decimos al usuario que estamos cargando un CSS (mediante los campos de cabecera), generamos los estilos y paramos la ejecución. No necesitamos cargarlo todo, sólo la parte que nos interesa. Lo vamos a ver mejor con un ejemplo:

De este código podemos sacar alguna pregunta: ¿Por qué plugins_loaded y no otro? Funcionaría en init por ejemplo, ¿Por qué no init entonces? Bueno, hay que recordar que la idea es cargar lo mínimo del núcleo de WordPress, además debe hacerse antes de que WordPress envíe las cabeceras. Esto se produce justo después de la ejecución del action template_redirect. Es decir, que podríamos utilizar éste último y aún así funcionaría pero ¿Para qué? Lo mejor es hacerlo lo antes posible. Si estamos desarrollando un plugin, el idóneo es justo cuando nuestro plugin ha cargado su código, esto es plugins_loaded pero si lo estamos haciendo para un Tema, el hook apropiado sería after_theme_setup. Aquí podemos ver una lista de actions y el orden de ejecución.

  • ¿Cómo generar la cabecera CSS y generar los estilos? Es muy sencillo generar una cabecera para nuestro supuesto fichero. Se usa la función header de PHP

Los pasos son sencillos: Generamos la cabecera de tipo text/css, recogemos las opciones de nuestro Plugin/Tema de Base de Datos y generamos las reglas CSS con los valores de las opciones.

Ahora ya sólo queda comprobar que todo funciona bien. Para esto, simplemente ponemos en el navegador la URL de nuestro CSS “virtual”. Deberíamos ver un fichero CSS normal y corriente.

La API de opciones de WooCommerce (II)

Continuamos con la serie de API Settings para WooCommerce. Si te has perdido la primera parte, aquí la tienes: https://holadolly.wordpress.com/2014/05/13/la-api-de-opciones-de-woocommerce-i/

En el episodio anterior añadimos campos simples a nuestra pantalla de opciones en WooCommerce. Dichos campos son gestionados automáticamente sin necesitar de código adicional para su validación o HTML para mostrar los campos, WooCommerce se encargaba de todo.

Pero no todos los campos son simples, lo más probable es que en algún momento necesitemos mostrar campos más complejos que requieran un tratamiento especial. Afortunadamente, WooCommerce viene preparado para esto y con sólo unas líneas más podemos hacerlo sin complicar la cosa demasiado. Para ello tenemos que seguir unos pocos pasos:

  1. Decirle a WooCommerce que nuestro campo se tratará de forma diferente y mostrar el HTML del campo
  2. Validarlo ya que WooCommerce no lo hará por si mismo..

1. Agregar un campo personalizado y mostrarlo por pantalla

En la primera parte creamos una clase que se encargaría de mostrar/validar nuestra pestaña de opciones. Dicha clase contenía un método llamado get_settings() que devolvía un array con las opciones a mostrar y todas sus características. Ahora simplemente vamos a añadir un registro más a dicho array que contendrá la información de nuestro nuevo campo especial:

Como vemos, nuestro nuevo campo tiene una ID , holadolly_general_options_special y un tipo holadolly_special_field que no reconoce WooCommerce. Si refrescamos la pantalla no veremos nada nuevo. La nueva opción no se muestra por pantalla. WooCommerce necesita una función especial para dicho campo. Para ello necesitaremos dos cosas: un nuevo hook y una nueva función en nuestra clase:

Si nos fijamos, en el constructor de la clase hemos añadido un hook nuevo que se compone de la siguiente manera:

add_action( 'woocommerce_admin_field_$tipo_de_nuestro_campo', $funcion_que_muestra_el_campo );

El tipo de campo lo definimos ya en el array dentro de get_settings() y la función (o método) que se encarga de mostrarlo es display_special_field( $field ) que recibe como parámetro todos los atributos que definen el campo.

Para que veamos mejor qué contiene la variable  $field se la pasamos a var_dump:

01 woocommerce-ii

 

Básicamente, el contenido es el mismo que el del array en get_settings().

A partir de esta información vamos a recoger de Base de Datos el valor de nuestra opción y mostrarlo en un área de texto, que va a ser nuestro campo especial. La función display_special_field( $field ) queda de la siguiente manera:

Gracias a get_option, recogemos el valor, si no lo encuentra tomará el valor que definimos en la propiedad default de nuestro campo. Luego generamos el código HTML para el área de texto cuya propiedad name será el ID del campo. Y ya está, lo podemos complicar todo lo que queramos pero el campo ya nos tiene que aparecer:

02 woocommerce-ii

 

Esto va bien pero si guardamos cambios, el valor del campo no se guarda en Base de Datos. ¡Toca validarlo!

 

2. Validación y guardado del campo especial

Como viene siendo costumbre, vamos a necesitar otro hook para que cuando WooCommerce haya terminado de guardar los campos, pase de nuevo por nuestra clase y guardemos el campo especial.

De manera similar al punto anterior, el hook tiene la siguiente composición:

add_action( "woocommerce_update_option_$tipo_de_campo", $funcion_que_valida_y_guarda_el_campo );

Así, nuestra clase queda tal que así:

La función que valida el campo la hemos llamado sanitize_special_field( $field ) donde $field tiene exactamente el mismo valor que en el punto anterior; los atributos de nuestro campo. Sólo hay que limpiarlo un poco (con stripslashes) y guardarlo mediante update_option.

Ahora sí, nuestro flamante nuevo campo funciona a las mil maravillas:

03 woocommerce-ii

 

En resumen

La nueva API Settings de WooCommerce nos ofrece muchísima flexibilidad para crear una nueva pestaña de opciones dentro de WooCommerce. Es altamente recomendable que nuestras opciones estén bien integradas en el plugin ya que evitará futuros fallos y además mejorará la facilidad de uso del interfaz para los usuarios habituales de WooCommerce.

WooCommerce provee más hooks para poder personalizar las pestañas como por ejemplo añadir links de secciones debajo de las pestañas (tal y como las opciones de envío o Emails tienen) pero simplemente investigando un poco el código se puede sacar. No obstante en Hola Dolly estamos abiertos a cualquier duda o pregunta que pueda enriquecer esta entrada.

Cómo saber si un hook se ha ejecutado ya

La respuesta es fácil pero no muchos conocen esta función:

La función devuelve 1 si el hook ya ha sido ejecutado y 0 si todavía está pendiente.

A veces también necesitaríamos saber todos los hooks que han sido ya ejecutados para saber cuál nos convendría más y si tenemos que cambiar partes de nuestro código para que funcione. En ese caso podemos usar el siguiente código, un poco más pedestre pero que puede llegar a sernos útil:

Aquí tenemos un ejemplo de la salida:

 

array (size=59)
  'muplugins_loaded' => int 1
  'registered_taxonomy' => int 15
  'registered_post_type' => int 14
  'woocommerce_loaded' => int 1
  'plugins_loaded' => int 1
  'sanitize_comment_cookies' => int 1
  'setup_theme' => int 1
  'load_textdomain' => int 17
  'after_setup_theme' => int 1
  'auth_cookie_valid' => int 2
  'set_current_user' => int 1
  'init' => int 1
  'before_woocommerce_init' => int 1
  'woocommerce_integrations_init' => int 1
  'woocommerce_init' => int 1
  'widgets_init' => int 1
  'register_sidebar' => int 3
  'wp_register_sidebar_widget' => int 25
  'woocommerce_register_taxonomy' => int 1
  'woocommerce_register_post_type' => int 1
  'update_option' => int 1
  'update_option__transient_doing_cron' => int 1
  'updated_option' => int 1
  'set_transient__transient_doing_cron' => int 1
  'setted_transient' => int 1
  'http_api_curl' => int 1
  'http_api_debug' => int 1
  'wp_loaded' => int 1
  'auth_redirect' => int 1
  'wp_default_scripts' => int 1
  '_admin_menu' => int 1
  'admin_menu' => int 1
  'admin_init' => int 1
  'wp_default_styles' => int 1
  'admin_bar_init' => int 1
  'add_admin_bar_menus' => int 1
  'current_screen' => int 1
  'load-woocommerce_page_wc-settings' => int 1
  'woocommerce_shipping_init' => int 1
  'woocommerce_load_shipping_methods' => int 1
  'admin_xml_ns' => int 2
  'admin_enqueue_scripts' => int 1
  'woocommerce_admin_css' => int 1
  'admin_print_styles-woocommerce_page_wc-settings' => int 1
  'admin_print_styles' => int 1
  'admin_print_scripts-woocommerce_page_wc-settings' => int 1
  'admin_print_scripts' => int 1
  'wp_print_scripts' => int 1
  'admin_head-woocommerce_page_wc-settings' => int 1
  'admin_head' => int 1
  'adminmenu' => int 1
  'in_admin_header' => int 1
  'admin_bar_menu' => int 1
  'wp_before_admin_bar_render' => int 1
  'wp_after_admin_bar_render' => int 1
  'admin_notices' => int 1
  'all_admin_notices' => int 1
  'woocommerce_page_wc-settings' => int 1
  'woocommerce_settings_start' => int 1

Otra función más que puede resultar interesante es aquella que nos permite saber qué hook se está ejecutando en este mismo momento (aunque realmente lo que no sdice es qué filtro fue el último en ejecutarse)

La API de opciones de WooCommerce (I)

Entre otros muchos cambios, WooCommerce 2.0 trajo una renovación completa de su Settings API. Aunque no es de mi total agrado ya que el encapsulado de clases no es óptimo, nos hace muchísimo más fácil añadir nuestra propia pestaña a las opciones de WooCommerce, una práctica más que recomendable si queremos extenderlo. Crear nuestro propio plugin para WooCommerce puede traer varias preguntas, una de ellas es ¿Dónde poner las opciones de nuestro plugin? Crear un nuevo submenú sería absurdo si ya disponemos de una pantalla que WooCommerce trae de serie y que podemos extender a nuestro antojo. Además, en muchos casos podemos aprovecharnos del sistema de validación que WooCommerce trae de serie.

A grandes rasgos, esto es lo que tendremos que hacer:

  1. Añadir nuestra propia pestaña en la pantalla de opciones de WooCommerce mediante un filtro y programar una nueva clase que se encargue de gestionar la pestaña.
  2. Crear las secciones necesarias dentro de dicha pestaña.
  3. Agregar campos a cada una de las secciones que hemos creado. Los campos pueden ser simples, ya sea un número o un campo de texto que WooCommerce podrá gestionar él solito.
  4. Es más que probable que necesitemos algún campo especial personalizado. Aquí no podremos hacer uso de las funciones que WooCommerce incorpora y tendremos que crearnos las nuestras propias.
  5. Validar los datos. De nuevo, WooCommerce se encargará de validar aquellos que ya lleva incorporado, para los nuestros será necesario picar un poco más de código.

Pues vamos allá.

1. Añadir nuestra propia pestaña en la pantalla de opciones de WooCommerce y programar una nueva clase que se encargue de gestionar la pestaña

Ésta es la típica imagen básica de las opciones de WooCommerce una vez instalado:

 

01-woocommerce_settings_tabs

 

Para que nuestro plugin esté completamente integrado con WooCommerce vamos a insertar una pestaña al final, después de Emails. Para ello vamos a crear primero un fichero que incluya una nueva clase que extiende de WC_Settings_Page. Dicha clase viene incluida en WooCommerce y se encarga de dar forma a cada una de las pestañas en la pantalla de opciones. Si revisamos el código de WooCommerce en includes/admin/settings/class-wc-settings-page.php podremos entender mejor porqué tenemos que extender de dicha clase pero requeriría un poco de tiempo explicarla a fondo. Es más o menos sencilla de entender si vamos mirando línea por línea.

Vamos a crear un nuevo fichero llamado class-wc-settings-holadolly.php dentro de nuestro plugin que importaremos más adelante. Aquí tenemos la estructura básica de la clase:

En el constructor de la clase tenemos la información necesaria para la pestaña. Toda pestaña necesita una ID y un título que son propiedades dentro de la misma clase pero lo que realmente incluye la pestaña es el hook que viene inmediatamente después, woocommerce_settings_tabs_array, que llama a un método llamado add_settings_page dentro de la clase padre, WC_Settings_Page. Dicho método no necesitamos implementarlo nosotros, la clase padre se encargará de recoger la ID y el título de la pantalla y mostrarlo correctamente. Por último el filtro incluye una prioridad que hemos puesto a 20 para que la pestaña se muestre al final de la cola.

Ojo con la última línea porque estamos creando una instancia de la clase nada más incluir el archivo (cosa que todavía no hemos hecho).

Por ahora la pantalla de opciones sigue igual. Nos falta incluir nuestra clase pero no podemos hacerlo de cualquier manera, WooCommerce provee un filtro especial para ello. Aquí va el código:

Los archivos que incluyen las clases que extienden de WC_Settings_Page se añaden dinámicamente mediante este filtro y se agregan a un array que WooCommerce ya tiene rellenado con las los archivos que WooCommerce incluye por defecto. Creo que es fácil entender lo que está pasando ahí. Nuestra clase se incluye y además se instancia, con lo que ya deberíamos ver nuestra pestaña:

02-holadolly-tab

 

Obviamente, aún queda por hacer, no hemos definido ninguna opción para nuestra pestaña.

 

 2. Crear las secciones necesarias dentro de dicha pestaña.

Toca empezar a jerarquizar nuestras opciones. Vamos a crear un par de secciones dentro de nuestra pestaña. Cada sección tendrá una serie de opciones que añadiremos más tarde. Por el momento dos bastarán: Una sección general (con campos que WooCommerce gestionará automáticamente) y otra especial (que tendremos que codificar nosotros mismos).

Para crear nuestras secciones tendremos que crear un nuevo método llamado get_settings dentro de nuestra clase WC_Settings_Hola_Dolly que la clase padre llamará automáticamente. Dicho método devolverá un array con toda la información sobre nuestras secciones/campos:

Lo primero que vemos es que en el constructor hemos añadido un filtro más, ‘woocommerce_settings_’ . $this->id, que llama a un método output() que no tenemos en nuestra clase pero que sí tiene la clase padre, WC_Settings_Page. Dicho método se encarga de sacar por pantalla las opciones que estamos generando. Si no usamos ese filtro no veremos nada.

El método get_settings devuelve un array con las dos secciones bien marcadas. Si nos fijamos, aunque hay dos secciones, dentro del array tenemos cuatro elementos. Toda sección debe llevar un elemento que abre la sección ( ‘type’ => ‘title’ ) y otro que la cierra ( ‘type’ => ‘sectionend’). Si nos olvidamos de cerrarlas la página no se comportará correctamente.

Como vemos, cada sección tiene una id a la que debemos hacer referencia tanto al abrir como al cerrar la sección. Además hay otra propiedad, desc, que incluye la descripción de la sección. Dicha propiedad no es obligatoria, simplemente es el texto que aparecerá al principio de cada sección. Existen más propiedades pero no hay espacio suficiente aquí para explicar cada una de ellas, lo mejor es bucear un poco por el código de WooCommerce.

La pantalla se nos queda tal que así:

03-settings-tab-with-sections

 

Esto, lógicamente no sirve para nada, si pulsamos el botón no estaremos guardando nada. ¿Qué tal si rellenamos las secciones con unos cuantos campos?

 

3. Agregar campos simples

WooCommerce puede manejar automáticamente campos sencillos (y otros que no lo son tanto): números, texto, email, color, contraseña, áreas de texto, selects, multiselects, radios, checkboxes, ancho de imagen, selector de página, selector de país y multiselector de país. Como vemos la lista no está nada mal pero entre todos ellos vamos a escoger uno muy sencillo: Campo numérico. Este campo lo vamos a poner dentro de la sección de Opciones Generales y tendremos que darle un valor por defecto, una id, un título, indicar de qué tipo es y quizás una descripción. Muy sencillo, sólo hay que tener en cuenta que las opciones por pantalla aparecen en el mismo orden que indicamos en get_settings(), dentro del array:

Poco hay que explicar aquí, nuestro nuevo campo se define con un array tal y como hemos dicho, con un título, una id (holadolly_general_options_number), un valor por defecto ( 0 ) y un tipo de campo (number). Además le hemos añadido una propiedad llamada desc_tip que mostrará un icono con un símbolo de interrogación que al pasar el ratón por encima nos mostrará dicho texto. Podríamos haber optado por una simple descripción utilizando una propiedad desc pero así vemos la flexibilidad que WooCommerce nos ofrece.

04-settings-with-number

 

Bien, el campo se muestra correctamente con su icono de interrogación, valor por defecto, título, etc. Si cambiamos el valor a 1 y guardamos… Nada, vuelve a 0 el valor. Hay algo que todavía tenemos que hacer y es una de las cosas que no me terminan de gustar del diseño de esta clase, no es importante pero puede resultar molesto. Necesitamos decirle a la clase padre que cuando pulsemos el botón de guardar, nos guarde las opciones. Se hace mediante un filtro en el constructor de nuestra clase:

save() es un método que incluye la clase WC_Settings_Page y que guardará todas las opciones que mostremos por pantalla automáticamente a menos que le indiquemos lo contrario. Si ahora cambiamos el valor del campo y guardamos, el valor quedará guardado en base de datos, sí, ¿Pero dónde? Si volvemos un poco más arriba veremos de nuevo que dicho campo lleva asociado una id, holadolly_general_options_number, que es precisamente el slug de nuestra opción. Para recoger el valor simplemente tenndremos que llamar a get_option():

get_option('holadolly_general_options_number')

 

Aquí tenéis el código entero (es un plugin normal y corriente): https://github.com/igmoweb/woocommerce-settings-api-explained

 

Conclusión de la primera parte

Hemos aprendido a añadir nuestra propia pestaña a las opciones de WooCommerce de una manera eficaz, bien integrada y que nos evita mucho código. Un campo simple como puede ser un campo numérico es muy fácil de crear y ni siquiera hemos tenido que implementar código para tratar y guardar en Base de Datos dicho campo, WooCommerce lo ha hecho todo por nosotros: Muestra el campo, lo valida y lo guarda. También hemos aprendido a recoger su valor para usarlo donde queramos, todo en unas pocas líneas de código.

En la segunda parte del artículo aprenderemos a usar campos más avanzados que ya tendremos que mostrar, validar y guardar por nosotros mismos.

Todo esto y mucho más, muy pronto en Hola Dolly 🙂