Imágenes responsive en WordPress

¿Que son las imágenes responsive?

Las imágenes reponsive son aquellas imágenes que automáticamente carga la mejor versión para la resolución de tu equipo, esto permite con una misma etiqueta HTML cargar una imagen de alta resolución para una computadora con pantalla HiDPI (Retina Display) y una imagen de baja resolución para un dispositivo móvil con una pantalla de baja calidad. (Si quieres leer mas documentación te recomiendo leer la entrada de <img> en MDN).

El código HTML necesario es como cualquier <img> para dar compatibilidad a las páginas existentes, pero adicionalmente se agrega un atributo srcset para poder especificar la imagen correspondiente a cada resolución y también se agrega el atributo sizes para definir las reglas de cuando usar cada imagen.

Cómo generar el código en WordPress

A partir de WordPress 4.4 ahora podemos contar imágenes responsive de forma automática, usando las funciones de este CMS obtendrás el código HTML para crear imágenes adaptables, pero probablemente si tienes algún código donde generabas las etiquetas de estas imágenes manualmente, necesitaras llamar a varias funcionales para hacerlo.

A continuación te explicare cómo es el proceso, el primer paso es obtener los valores de los atributos src y srcset, en este caso pasamos full como tamaño para obtener la imagen en su mayor resolución:

$img_src = wp_get_attachment_image_url( $attach_id, 'full' );
$img_srcset =  wp_get_attachment_image_srcset( $attach_id, 'full' );

Generamos la etiqueta sizes para los tipos de imágenes que queremos mostrar:

$wp_sizes   = array('full', 'large', 'medium', 'thumbnail');
$img_sizes  = '';

foreach ( $wp_sizes as $wp_size ) {
   $img_sizes .=  wp_calculate_image_sizes( $wp_size,  $img_src, null,  $attach_id );
}

Luego podemos generar el HTML de la etiqueta img:

$img = sprintf('<img src="%s" srcset="%s" sizes="%s" alt="%s" >',
   esc_url( $img_src ), esc_attr( $img_srcset ), esc_attr($img_sizes), $img_alt
);

Listo, ya tendrás una etiqueta de imagen responsiva donde dependiendo de la resolución del dispositivo, se cambiará la imagen por una de mayor o menor de resolución (dependiendo del dispositivo). Cabe destacar que esta funcionalidad funciona con todo navegador moderno exceptuando…por supuesto…Internet Explorer.

Cómo ordenar de forma personalizada elementos en Woocommerce

En Woocommerce, puedes ordenar el listado de productos de varias formas en Ajustes -> Productos -> Ordenamiento de Productos por defecto, pero si en alguna parte del sitio necesitas crear tu propio listado a través de una consulta (generalmente mediante WP_Query) a la base de datos, lo mas probable es que desees mantener el orden establecido en ese apartado.

La manera de mantener el orden, es extraer esa configuración inicial mediante el objeto global $wp_query, pues posee la información por defecto (o la modificada por el usuario) para realizar una consulta, así que accediendo a los atributos order, orderby y enviando ambos al la consulta, obtendrás el orden de la configuración inicial, tal como se muestra en el siguiente ejemplo:

$args = array(
   'posts_per_page' => -1,
   'post_type'      => array('product'), //Para consultar solo los productos
   'product_cat'    => $category, //Me traigo una categoria deseada
   'order'          => $wp_query->get('order'), //Trae el orden seleccionado en frontend
   'orderby'        => $wp_query->get('orderby') //Trae el atributo de orden seleccionado en el frontend
);
$loop = new WP_Query( $args );

Recuerda que debes previamente traer el objeto global $wp_query y luego con el resultado de la consulta, la puedes recorrer con los métodos normales de WordPress.

Hace 5 años en esa fecha: Liberado jQuery Categories List 1.1

Cómo enviar los correos electrónicos predefinidos de Woocommerce

Woocommerce es una excelente herramienta para montar tu propia tienda en línea, es fácil de instalar y usar gracias que está construida sobre WordPress. Ademas es posible modificar todo su comportamiento mediante la instalación o construcción de plugins.

Hace unas semanas construyendo un plugin para cambiar el flujo normal de los estados de una orden, me tocó enviar los correos predefinidos (nueva orden, orden procesada, etc) manualmente. Para mi sorpresa no encontré documentación sobre como hacerlo, y al leer el código fuente de la clase para enviar correos, me dí cuenta que posee estructura extraña porque utiliza muchos hooks y variables globales, así que me costó hacerlo.

Envío de correos

Woocommerce posee una clase llamada WC_Emails (no confundir con WC_Email que es abstracta para definir una plantilla de correo) cuya tarea es cargar todas las plantillas de correos definidas y posee métodos para enviar el correo. Pues simplemente se debe seleccionar una de las plantillas disponibles y ejecutar el método trigger con los parámetros requeridos para enviar el correo electrónico, es importante NO instanciar un objeto desde esta clase, pues al momento de crearse se instancia ciertas cosas de la plantilla y se ejecutan, ocasionando bugs como repetición del encabezado y ejecución múltiple de hooks.

Por ello, solo debemos llamar a la función WC()->mailer() que siempre nos devuelve el objeto global de WC_Emails, seleccionamos la plantilla en el atributo emails, podemos personalizar el texto del sujeto o encabezado del correo y finalmente se ejecuta el método trigger con los parámetros del contenido del correo (los cuales varían en cada plantilla), tal como se puede observar en el siguiente ejemplo:


$wcEmail = WC()->mailer();
$emailer = $wcEmail->emails['WC_Email_Customer_Note']; //Enviar una nota al usuario
$emailer->subject = $subject; //Sujeto del correo
$emailer->heading = $title; //Título del contenido del correo
$emailer->trigger(array(
   'order_id' => $order_id, //Número de la orden
   'customer_note' => $msg  //Contenido de la nota
));

Las plantillas de correo disponibles por defecto (ya que puedes agregar tus propias plantillas) son:

  • WC_Email_New_Order
  • WC_Email_Cancelled_Order
  • WC_Email_Customer_Processing_Order
  • WC_Email_Customer_Completed_Order
  • WC_Email_Customer_Refunded_Order
  • WC_Email_Customer_Invoice
  • WC_Email_Customer_Note
  • WC_Email_Customer_Reset_Password
  • WC_Email_Customer_New_Account

En caso de necesitar los parametros, simplemente chequeen los archivos con las clases. El nombre del archivo es la misma constante pero todo en minúsculas y cambiando piso por guiones, por ejemplo, WC_Email_Customer_Invoice está definido en el archivo wc-email-customer-invoice.php. Es fácil, aunque parezca lo contrario. Pero descubrir esta información me tomó tiempo al tener que chequear el código fuente de los correos en woocommerce, así que espero que les haya servido de gran ayuda y ahorra de tiempo.

Hace 7 años en esa fecha: Amarok 2 disponible ahora en Windows

Como agregar rutas personalizadas en el API REST de Woocommerce

Woocommerce es una excelente plataforma para montar tu propia tienda en línea. Aunque mucha gente piensa que WordPress sigue siendo solo una plataforma para blogs, desde hace años se ha cambiado el funcionamiento interno para soportar todo tipo de contenido. Woocommerce es un ejemplo de ellos, pues este plugin permite soportar todo el contenido requerido en una tienda en línea como: productos, órdenes, pagos, descuentos, entre otros.

API REST

El plugin incluye una API REST para las operaciones mas básicas (se debe activar previamente), permitiendo comunicación hacia o desde aplicaciones externas, extendiendo aún mas las posibilidades de procesos que se pueden implementar en la tienda. Sin embargo, si manejas flujos de compras personalizados o deseas realizar acciones mas allá de las disponibles en el API por defecto, puedes agregar las tuyas tal como se explicará a continuación.

Desarrollo del plugin

El plugin se divide en 2 archivos, el principal para definir el plugin como tal y permitirle indicar a WordPress en que momento se va a cargar el segundo archivo, que contiene los métodos que responden a las rutas personalizadas del API.

Cargador de la clases

Para modificar WordPress, siempre es recomendable hacerlo a través de plugins, por eso el primer paso es definir un plugin como cualquier otro y dentro del constructo de la clase del plugin, indicar a Woocommerce que luego de cargar el código necesario para implementar el API (a través del hook woocommerce_api_loaded) se deben agregar la(s) clase(s) que implementan las rutas personalizadas (a través del hook woocommerce_api_classes), este código lo pueden ver a continuación:


/**
 * Plugin Name: Woocommerce custom path example
 * Description: Custom API calls plugin
 * Version: 1.0
 * Author: Miguel Useche
 * Author URI: http://migueluseche.com
 * License: GPL 3.0
 *
 * @package MyPlugin
 */

 
if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}

if (!class_exists('WD_API_LOADER')) {

    /**
     * Main plugin class
     *
     * @package MyPlugin
     * @author Skatox
     */

    class WD_API_LOADER
    {
        public function init()
        {
          add_action( 'woocommerce_api_loaded', array( $this, 'load' ) );
        }

        public function load()
        {
            require_once plugin_dir_path( __FILE__ ).'wc-api-custom.php';
            add_filter( 'woocommerce_api_classes', array( $this, 'register' ) );
        }

        public function register( $api_classes=array() )
        {
          array_push( $api_classes, 'WC_API_Custom' );

          return $api_classes;
        }
    }
}

$wc_custom_api = new WD_API_LOADER();
$wc_custom_api-&gt;init();

Leyendo observarán que es un plugin de WordPress donde la clase WD_API_LOADER registra los hooks mencionados anteriormente, para inyectar en el momento que Woocommerce carga sus clases del API, las clases que instancia los procesos personalizados a ser implementados en el API.

Al final es recomendable instanciar la clase en un objeto, de este modo es posible acceder a los métodos de forma global desde plugines externos, como por ejemplo para detener la carga de las clases o implementar modificaciones permitiendo dar mayor flexibilidad al plugin.

Clase con los métodos de la API REST

El siguiente paso corresponde a crear la clase que responde a las peticiones HTTP del API. En este ejemplo, se define una constante con el PATH personalizado y en el constructor se definen las rutas personalizadas y el método que se debe llamar que responderá a la petición realizada. Si observas, el parámetro recibido es un array donde la llave representa la ruta relativa del API y como valor, otro arreglo con el nombre de la función a procesar la petición y las banderas del tipo de petición. Estas últimas banderas permiten definir el tipo de petición a recibir, por ejemplo
WC_API_Server::READABLE indica que lee datos desde la petición tal como es una petición GET,
WC_API_Server::ACCEPT_DATA permite decir que lea el cuerpo de la petición y permite leer información para peticiones POST y PUT, entre otros.


/**
 * Custom API REST path  class
 *
 * @package MyPlugin
 * @author Skatox
 */

class WC_API_Custom extends WC_API_Resource
{

    const PATH = '/custom';

    /**
     * Function to define each of the custom path
     */

    public function register_routes($routes)
    {
        //GET Request
        $routes[self::PATH . '/orders'] = array(
            array(array($this, 'listShippingOrders'), WC_API_Server::READABLE),
        );

        //POST Request
        $routes[self::PATH . '/orders/(?P&lt;order_id&gt;\d+)/fulfillments.json'] = array(
            array(array($this, 'createItem'), WC_API_Server::CREATABLE | WC_API_Server::ACCEPT_DATA),
        );

        //PUT Request
        $routes[self::PATH . '/variants/(?P&lt;id&gt;\d+).json'] = array(
            array(array($this, 'updateItem'), WC_API_Server::EDITABLE | WC_API_Server::ACCEPT_DATA),
        );

        return $routes;
    }

    public function listShippingOrders($fields = null, $filter = array(), $status = null, $page = 1)
    {
        $wcApiOrders = new WC_API_Orders($this-&gt;server);
        $orders = $wcApiOrders-&gt;get_orders($fields, $filter, $status, $page);

        //Removes orders without shipping methods
        foreach ($orders['orders'] as $key =&gt; $oreder)
        {
            if (empty($oreder['shipping_methods'])) {
                unset($oreders['orders'][$key]);
                continue;
            }
        }

        return $order;
    }

    public function createItem($order_id, $data)
    {
        //Do insert proccess and then return the response array
    }

    public function updateItem($id, $data)
    {
        //Do update proccess and then return the response array

    }
}

Una vez que proceses la petición, si necesitas devolver un objeto JSON, simplemente debes retornar un array con la información deseada y automáticamente Woocommerce se encargará de transformarlo en un objeto JSON e imprimirlo en la salida.

Recomendaciones

Como podrás observar, no es difícil. En caso que no sepas como desarrollar debido a la poca documentación. Te recomiendo leer el código fuente de las clases del API de Woocommerce, son fáciles de entender, creadas por el mismo equipo del plugin y verás como están creados los métodos existentes. Una de las mejores clases para guiarte, es la de productos que se encuentra ubicada en la ruta wp-plugins/woocommerce/includes/api/class-wc-api-products.php, pues es muy completa y posee todas las operaciones REST soportadas.

Recuerda crear un plugin para esto, evita colocarlo en el functions.php pues será difícil de mantener y dificulta migrar de tema (porque el API dependerá de ésta). Finalmente, recuerda respetar el estándar REST, he visto gente que implementa todo en POST y agrega incompatibilidades a aplicaciones.

Ya depende de tu imaginación, descubrir como extender las funcionalidades de Woocommerce a través de un API REST personalizado.

Mis artículos en la semana de WordPress de Oja.la

En el blog de Oja.la, están celebrando la semana de WordPress y publicarán una serie de mis artículos (con un poco de mas mejoras y mas contenido) sobre este maravilloso CMS. Así que les invito leer el blog de Oja.la y aumentar sus conocimientos de WordPress.

A continuación les dejo enlazado el primer artículo publicado sobre como aumentar la seguridad de WordPress en 2 pasos.