X
Back to the top

Wordpress

Crear página de opciones en WordPress con ACF

Vamos a ver cómo crear una página de opciones en el admin de WordPress facilmente con el plugin ACF (Advanced Custom Fields)

Lo primero que necesitamos es crear la sección en el admin, para posteriormente añadirle los campos que necesitemos.

En el codex de WordPress podemos encontrar la función add_menu_page que nos permite crear una sección en su admin, permitiéndonos un control más avanzado de ella, pero en el caso que nos ocupa, usaremos la API del plugin Advanced Custom Fields (ACF).

Según la documentación oficial del plugin, disponemos de la función acf_add_options_page para ello:

if( function_exists('acf_add_options_page') ) {		
    acf_add_options_page(array(
        'page_title' 	=> 'My Options',
        'menu_title'	=> 'My Options',
        'menu_slug' 	=> 'my-options-page',
        'capability'	=> 'edit_posts',
        'redirect'	=> false
    ));
}

En gist he creado un plugin simple con esta funcionalidad, así no vamos «ensuciando» nuestro functions.php, lo tenéis disponible aquí.

Una vez tenemos disponible nuestra sección de opciones, pasaremos a añadirle campos personalizados con la interfaz de diseño que nos ofrece ACF.

Cuando creamos un grupo de campos, simplemente tenemos que indicar que los ubique en la página de opciones que hemos creado (en este caso, la hemos llamado ‘Festivos’).

Ahora si que tenemos ya nuestra página de opciones 100% disponible para su uso.

¿Y cómo se accede al valor de dichas opciones?

ACF en su afán de hacernos la vida muy fácil, nos permite usar la función get_field para ello.

En este caso en concreto, dicha función deberemos usarla con el segundo parámetro con el valor ‘option’ (siempre ‘option’, independiente de como se llame nuestra sección). En la página de documentación oficial podemos entrar más información.

Si necesitamos obtener el valor del campo creado, por ejmplo, ‘titulo_festivo’:

$variable = get_field('titulo_festivo', 'option');

Un ejemplo de uso, para cuando tenemos un repeater en la página de opciones creada, podría ser:

$dias = array();
if( have_rows('festivos', 'option') ) {
    while( have_rows('festivos', 'option') ) {
        the_row();
        $dias[] = get_sub_field('festivo');
    }
}

Y con estos sencillos pasos, podemos disponer de páginas de opciones tan avanzadas como queramos, sin complicarnos en complejas codificaciones.

Crear pestaña en la página Mi Cuenta de Woocommerce

En ocasiones necesitamos añadir una nueva pestaña en la página «Mi Cuenta» que nos genera Woocommerce.
Imaginemos por ejemplo una sección dónde añadir un formulario de contacto personalizado de soporte premium para nuestros compradores.
A continuación muestro un código ejemplo en el que se usan los hooks y actions necesarios para conseguirlo.
Podéis ver el artículo original en businessbloomer.

/**
 * @snippet       WooCommerce Add New Tab @ My Account
 * @how-to        Watch tutorial @ https://businessbloomer.com/?p=19055
 * @author        Rodolfo Melogli
 * @compatible    WooCommerce 3.5.7
 * @donate $9     https://businessbloomer.com/bloomer-armada/
 */
  
// ------------------
// 1. Register new endpoint to use for My Account page
// Note: Resave Permalinks or it will give 404 error
  
function bbloomer_add_premium_support_endpoint() {
    add_rewrite_endpoint( 'premium-support', EP_ROOT | EP_PAGES );
}
  
add_action( 'init', 'bbloomer_add_premium_support_endpoint' );
  
  
// ------------------
// 2. Add new query var
  
function bbloomer_premium_support_query_vars( $vars ) {
    $vars[] = 'premium-support';
    return $vars;
}
  
add_filter( 'query_vars', 'bbloomer_premium_support_query_vars', 0 );
  
  
// ------------------
// 3. Insert the new endpoint into the My Account menu
  
function bbloomer_add_premium_support_link_my_account( $items ) {
    $items['premium-support'] = 'Premium Support';
    return $items;
}
  
add_filter( 'woocommerce_account_menu_items', 'bbloomer_add_premium_support_link_my_account' );
  
  
// ------------------
// 4. Add content to the new endpoint
  
function bbloomer_premium_support_content() {
echo '<h3>Premium WooCommerce Support</h3><p>Welcome to the WooCommerce support area. As a premium customer, you can submit a ticket should you have any WooCommerce issues with your website, snippets or customization. <i>Please contact your theme/plugin developer for theme/plugin-related support.</i></p>';
echo do_shortcode( ' /* your shortcode here */ ' );
}
  
add_action( 'woocommerce_account_premium-support_endpoint', 'bbloomer_premium_support_content' );
// Note: add_action must follow 'woocommerce_account_{your-endpoint-slug}_endpoint' format

Permisos de archivos correctos

Cuando hablamos de seguridad web, uno de los puntos principales a tener en cuenta es tener los permisos de archivos correctos.
Pensemos que en realidad lo que estamos sirviendo a través de nuestra web, no son más que ficheros, que se ejecutan y generan unos resultados.
Permitir que ciertos usuarios puedan escribir o ejecutar archivos, puede suponer una brecha de seguridad grave, pudiendo incrustar código malicioso, nuevo archivos o correr scripts que nos pongan en compromiso.
Pero, ¿cuales son los permisos de archivos correctos?
En un entorno de producción, visible al público, deberíamos tener:

  • Permisos 644 para los archivos.
  • Permisos 755 para las carpetas.

¿Qué nos indican estos números?

Permisos de archivos (0644)

6 (110): Permisos de lectura y escritura para el dueño del archivo (quien lo creó)
4 (100): Permisos de sólo lectura para los miembros del grupo del dueño del archivo.
4 (100): Permisos de sólo lectura para el resto de usuarios.
Es decir, que salvo el dueño del archivo, ningún otro usuario podrá modificar el archivo o ejecutarlo.

Permisos de carpetas (755)

7 (111): Permisos de lectura, escritura y ejecución sobre la carpeta para el dueño de la carpeta (quién la creó)
5 (101): Permisos de lectura y ejecución sobre la carpeta para los usuarios del mismo grupo que el dueño de la carpeta.
5 (101): Permisos de lectura y ejecución sobre la carpeta para el resto de usuarios.
Es decir, sólo los dueños de las carpetas podrá escribir en ellas.

Permisos especiales

Hay una serie de bits especiales para los archivos que otorgan ciertos privilegios extras.
Entre ellos vamos a destacar SUID y SGID que hacen que el usuario que ejecuta un determinado archivo adquiera los privilegios del usuario (si es SUID) o grupo (SGID) que creó el archivo.
Como se puede pensar esto puede ser muy grave, ya que si por algún motivo un usuario root crea un archivo y tiene estos bits activos, el usuario X que pueda ejecutar dicho archivo, tendrá temporalmente los privilegios de root.
En este artículo podemos leer más información sobre dichos archivos.

Acabamos de ver que tener en cuenta los permisos de archivos es de prioridad máxima, pero no olvidemos tener en cuenta otros aspectos que iré incluyendo en la sección de Seguridad WordPress del blog.

Tricks WordPress

Desactivar Gutemberg

// Desactivamos gutemberg
add_filter('use_block_editor_for_post_type', '__return_false', 100);

Si no vamos a usar Gutemberg, no tiene sentido que carguemos su css, por lo que evitamos cargarlo:

function dequeue_gutenberg_theme_css() {
    wp_dequeue_style( 'wp-block-library' );
}
add_action( 'wp_enqueue_scripts', 'dequeue_gutenberg_theme_css', 100);

Ya que estamos en modo ahorro, ¿qué tal si evitamos cargar los emojis y mejoramos nuestro WPO (Web Performance Optimization) un poco más?

remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'wp_print_styles', 'print_emoji_styles' );
remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
remove_filter( 'the_content_feed', 'wp_staticize_emoji' );
remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );

Sanitizar los nombres de archivos, para evitar ñ y demás caracteres extraños (código dado por el crack @fpuenteonline):

/* Evitamos que se añadan caracteres raros a los nombres de archivos */
function sanitize_filename_on_upload($filename) {
	$ext = end(explode('.',$filename));
	$sanitized = preg_replace('/[^a-zA-Z0-9-_.]/','', substr($filename, 0, -(strlen($ext)+1)));
	$sanitized = str_replace('.','-', $sanitized);
	return strtolower($sanitized.'.'.$ext);
}
add_filter('sanitize_file_name', 'sanitize_filename_on_upload', 10);

Si tenemos un sitio en el que los usuarios se pueden loguear, quizás necesitemos ocultarles la barra de administrador. Con este pequeño trozo de código lo tendríamos (para todos los usuarios menos los admministradores, y sólo en el front).

/* Ocultamos la barra de administrador si no eres admin */
add_action('after_setup_theme', 'remove_admin_bar');
function remove_admin_bar() {
    if (!current_user_can('administrator') &amp;amp;amp;&amp;amp;amp; !is_admin()) {
        show_admin_bar(false);
    }
}

Revisiones sólo guardamos 3

define( 'WP_POST_REVISIONS', 3 );

Vaciamos la papelera cada x días

define('EMPTY_TRASH_DAYS', 7);

Desactivar la actualización automática de WordPress.
Se recomienda estar siempre actualizado, pero a nivel personal, me gusta controlar cuándo y cómo se actualizan mis webs, para hacerlo de forma manual y supervisada.

define( 'WP_AUTO_UPDATE_CORE', false );

Eliminar custom post type y taxonomías

En ocasiones necesitamos eliminar custom post type (CPT) y taxonomías que no vamos a necesitar, y que bien por algún plugin de tercero, o por tema WordPress se nos han instalado en nuestra web.
Este caso lo solemos encontrar cuando compramos algún tema premium, por ejemplo en Themeforest, y dicho tema trae custom post types que no vamos a usar, por lo que lo correcto son eliminarlos.
Pero no eliminarlos sólo a nivel de contenido desde el dashboard, sino también a nivel de código, para evitar que los buscadores puedan indexarlos.
Para desinstalarlos, vamos a usar estos snipers, que podremos poner bien en nuestro propio plugin, o en el fichero functions.php del tema hijo que usemos.

if( !function_exists( 'unregister_cpt_tax' ) ) {
    function unregister_cpt_tax(){
        unregister_post_type( 'project' );
        unregister_taxonomy( 'project-cat' );
    }
}
add_action('init','unregister_cpt_tax');

Este código en concreto eliminaría el custom post type ‘project’, y la taxonomía ‘proyect-cat’

Y de esta forma rápida y sencilla nos quitamos de encima la ‘basura’ que en ocasiones nos traen las plantillas.

Tips seguridad extra en WordPress

A añadir en el fichero functions.php:

// Desactivamos Rest API
add_filter('json_enabled', '__return_false');
add_filter('json_jsonp_enabled', '__return_false');
function restrict_rest_api_to_localhost() {
    die('REST API is disabled.');
}
add_action( 'rest_api_init', 'restrict_rest_api_to_localhost', 1 );

// Eliminamos las versiones visibles de wordpress
remove_action('wp_head', 'wp_generator');
// remove version from rss
add_filter('the_generator', '__return_empty_string');

// Añadimos directivas de seguridad en la cabecera
add_action( 'send_headers', 'add_header_security' );
function add_header_security() {
    header( 'X-Content-Type-Options: nosniff' );
    header( 'X-Frame-Options: SAMEORIGIN' );
    header( 'X-XSS-Protection: 1' );
}
Diagrama de caso de suso -Membership site

Membership site con WordPress

En este caso de estudio, vamos a montar un membership site con WordPress, es decir, vamos a vender nuestro conocimiento o productos de forma periódica.

Caso de uso

Llevamos ya muchos años dedicados al mundo de la programación web, especialmente al CMS WordPress, y dándole vueltas a la cabeza hemos decidido «vender» nuestro conocimiento. Es por ello por lo que nos surge la idea de montar un site en el que iremos escribiendo de forma periódica artículos sobre programación WordPress, con tutoriales de cómo hacer esto y lo otro.

Además de ello, mediante el sistema de comentarios de WordPress, daremos soporte premium a los miembros de nuestro site, dándoles un valor añadido al hecho de suscribirse.

Diagrama de caso de suso -Membership site

Implementación de la solución

Empezando desde el principio, montaremos nuestro WordPress, al que añadiremos las funcionales adicionales que iremos necesitando.

Sistema de membersía.

Usaremos el plugin Groups, de @itthinx, que nos permite entre otras muchas cosas, crear tantos grupos de usuarios como necesitemos, y asignarlos a ellos.

En nuestro caso, tendremos sólo un nivel de pago, por lo que tendremos el grupo Registered (por defecto de WordPress), y un grupo Premium, donde estarán los usuarios miembros de nuestra comunidad.

Con Groups, podemos decidir quien tiene acceso a un determinado post, y quien no. Por lo que podremos crear nuestra tanda de artículos premium sólo disponibles para nuestros miembros especiales.

 

Esto hará que si un usuario no Premium intenta acceder al artículo, sea redireccionado a la página 404 de la web.

Pero ¿qué tal si mejoramos esto, y lo redireccionamos a una landing page donde podremos colocar un CTA (call to action) que le motive a registrarse? La extensión Groups 404 redirect nos lo permitirá.

Ya tenemos nuestro contenido restringido, la definición de los grupos de usuarios, y ¿que nos falta?, pues lo importante, «pasar por caja».

Groups nos permite multitud de conexiones con carros de compras, como puede ser con Woocommerce, pero en nuestro caso, como sólo vamos a tener 1 producto, sería matar moscas a cañonazos, así que vamos a usar la integración con Paypal, para crear un botón de pago y poder vender la membersía (en la página de documentación de la extensión, podemos ver más información de cómo configurarla)

Crearemos una página de venta y registro siguiendo las indicaciones da la empresa desarrolladora.

Con estos sencillos pasos ya tendríamos nuestro negocio en marcha, preparado para generarnos dinero.

Hagamos algunas mejoras y extensiones de funcionalidad.

Para mejorar nuestro SEO, y ofrecer a los usuarios una pequeña muestra de nuestro conocimiento, podríamos mostrar parte de los contenidos de los artículos, usándolos además como ganchos. Es por ello, por lo que desde Groups tenemos disponible los shortcodes [groups_member] y [groups_non_member].

 

 

Woocommerce Role Pricing

Tienda Woocommerce con descuentos para distribuidores

En este caso de uso, vamos a montar una tienda Woocommerce con descuentos para distribuidores, comerciales, clientes especiales o cualquier otro rol de usuario que tengamos.

Caso de uso

No todos nuestros clientes online son iguales, y por ello en ocasiones vamos a necesitar aplicarles descuentos según su rol en nuestro negocio. Tenemos por ejemplo:

  • El usuario fiel, que compra una y otra vez, y que ya es hora de agradecérselo.
  • Nuestra red de comerciales necesitan poder ofrecer los productos con un precio algo reducido, y contar con un incentivo para que el cliente final les compre.
  • Tenemos una tienda cuyo público puede ser el usuario final, o distribuidores (incluso usuarios dropshipping), por lo que los distribuidores deberían ver los precios rebajados con respecto al usuario final.

¿Qué necesitamos?

Para variar, vamos a montar nuestra solución basándonos en el CRM WordPress, y cómo no, en el plugin para tienda por excelencia, Woocommerce.

Con eso ya tenemos nuestra tienda online montada, ¿y ahora qué? …. pues vamos a montar nuestro sistema de descuentos.

Empezamos creando nuestra estructura de roles, teniendo:

    • Customer: Comprado básico definido por Woocommerce.
    • Premium: Usuarios fieles, a los que ofreceremos un 5% de descuento.
    • VIP: Usuarios «aún más fieles», con un descuento por defecto del 10%.
    • Comercial: Role que usarán Juan y Beatriz, nuestros comerciales, que contarán con un descuento del 15%, con el que poder jugar en las negociaciones.
    • Distribuidor: Role creado para los distribuidores, a los que queremos aplicar un 25% de descuento.

Para la creación de los distintos roles, usaremos el plugin User Role Editor, con lo que podremos crear tantos como necesitemos, y asignarlos a los distintos usuarios.

User Role Editor

Para montar los distintos descuentos aplicados por defecto, usaremos el plugin Woocommerce Role Pricing, inicialmente con su versión gratuita disponible en el repositorio de WordPress, y en caso de que necesitemos las funcionalidad extras, podemos pasar a la versión Pro, disponible en mi tienda online eggemplo.com.

Woocommerce Role Pricing

Podemos pensar, que para qué montar todo esto si aplicando cupones podemos dar descuentos especiales a cada usuario. Pero la principal ventaja de dicho plugin es que se aplican los descuentos o precios finales directamente sobre toda la tienda, con lo que el usuario ve la tienda ya con sus precios adaptados.

Entre las opciones que dispone, podemos aplicar descuentos en porcentajes o precios fijos, pudiendo por ejemplo aplicar un 10% de descuento, o 1€ a todos los productos.

Todas estas y más opciones las tenemos disponible en la versión gratuita.

Woocommerce Role pricing opciones

Y si tenemos todo esto gratis, ¿tiene sentido pasarnos a la versión Pro de pago?, la respuesta es que depende de nuestras necesidades:

  • Entre las opciones avanzadas disponibles, destaca la de poder aplicar descuentos o precios específicos para los distintos productos, pudiendo tener un 10% de descuento en toda la tienda, pero si en un producto en concreto tenemos menos margen de beneficio, podemos aplicar por ejemplo un 5%.
  • Es importante en ocasiones mostrar tanto el precio original, como el precio final, así conseguimos que el usuario sea consciente de las ventajas que tiene al comprar en nuestra tienda.

 

 

 

Cómo montar una página corporativa con WordPress

Uno de los casos de uso más frecuente con el que nos encontramos habitualmente en el desarrollo WordPress, es montar la página corporativa de una empresa, donde mostrar los datos de contacto, así como información propia de la empresa.

Casos de uso

Desde el punto de vista de la empresa, nos encontramos con el siguiente caso de uso:

<< Imagen del caso de uso con actor el empresario >>

Teniendo como actor al usuario final, tendríamos:

<< Imagen del caso de uso teniendo como actor al usuario final de la web >>

Estructura web

Viendo las necesidades que hemos recabado, decidimos estructurar la web con las siguientes secciones:

  • Portada : Página de bienvenida.
  • La empresa : Información corporativa de la empresa y sus socios.
  • Productos : Información sobre los productos que vende la empresa.
  • Servicios : Información sobre los servicios que ofrece la empresa.
  • Blog : La página tendrá un blog, donde poder hablar de información relacionada con la empresa, y hacer inbound marketing, y usarlo para atraer posibles clientes.
  • Contacto : Página con información de contacto.

A estas páginas, habría que añadir las páginas que contienen los datos legales de la empresa, como son:

  • Política de cookies : Deberemos informar de las distintas cookies que usamos, y para que las necesitamos.
  • Política de privacidad : Información sobre qué vamos a hacer con los datos que recabamos de los usuarios. Esto lo necesitamos, ya que tenemos un formulario de contacto, donde pedimos información a los usuarios.

Vayamos sección por sección, más centrándonos en un layout genérico y módulos necesarios, más que en estética y datos concretos.

Portada

Usaremos esta sección como escaparate principal, ya que será la página de aterrizaje (landing page) donde suelen llegar los usuarios por primera vez.

El layout a usar será:

<< Imagen del layout de la portada >>

Con un slider principal con imágenes destacadas.

Seguido de una breve descripción de bienvenida o informativa de la empresa.

A continuación una muestra de los servicios y productos destacados.

Y terminamos con un pie de página con la información de copyright, enlaces legales y redes sociales.

La empresa

Proximamente …

Productos

Proximamente ….

Servicios

Proximamente ….

Blog

Proximamente ….

Contacto

Proximamente ….

Enlaces externos

A continuación se indican enlaces a los distintos plugins usados para llevar a cabo la implementación de este caso de uso.

Proximamente ….

 

 

Diagrama Modelo Vista Controlador

Modelo vista controlador en WordPress

Vamos a aplicar el patrón de diseño software Modelo-Vista-Controlador en el desarrollo de plugins y temas WordPress.

El patrón de diseño software

Estamos ante uno de los patrones de diseño más usado en el desarrollo software. Se considera uno de los básicos a la hora de estructurar los proyectos.

Con él se consigue desacoplar la capa que muestra los datos en la interfaz, con la capa del modelo de datos. Todo ello a través de una capa de controladores, que se encargarán de que ambas partes «se entiendan».
En el siguiente esquema podemos ver su estructura:

Diagrama Modelo Vista Controlador

Este desacoplo nos permite por ejemplo cambiar el sistema de almacenar los datos, sin que la «aplicación pública» se vea comprometida. Es más, ese cambio sería 100% transparente para el usuario. Podemos por ejemplo pasar de tener los datos en una base de datos MYSQL, a tenerlos en un sistema de archivos en el servidor.

O nos permitiría por ejemplo, cambiar la vista de los datos, de html a un feed rss sin que el modelo de datos se vea alterado con ello.

Caso de uso

Vamos a implementar un portal para una inmobiliaria, en la que mostrar a los usuarios las propiedades disponibles, y poder solicitar información sobre ella.

Aplicándolo al desarrollo de plugins

La funcionalidad principal del portal será implementada a través de un plugin, al que llamaremos realhouse.
Veamos las distintas partes que componen el patrón de diseño MVC (modelo vista controlador), en nuestro plugin:

Estructura de carpetas del plugin

  • Vista: Usaremos shortcodes para mostrar la información en el frontend. A modo de referencia del código a mostrar, crearemos el shortcode: realhouse_search, que nos mostrará un buscador avanzado de propiedades.
  • Controlador: Crearemos clases que harán de controladores entre la vista y el modelo de datos. Desacoplando las vistas del modelo de datos.
  • Modelo: De los distintos modelos que contendrá el sistema, y que representarán las entidades «del mundo real», nos centraremos en el modelo que implementa a las propiedades inmobiliarias.

El flujo de información y peticiones que se producen en el patrón Modelo Vista Controlador, lo podemos ver en el siguiente diagrama de secuencia:

Diagrama de secuencia MVC

 

1: La vista necesita consultar el listado de propiedades, por lo que se lo pide al controlador.

1.1: El controlador al recibir la consulta, pide al modelo de datos la información requerida.

1.1.1: El modelo de datos devuelve al controlador la información que se le pidió.

1.1.1.1: El controlador, que ya tiene los datos disponibles, se los revuelve a la vista, para que pueda mostrar por pantalla dicha información.

Como podemos ver, en ningún momento la vista sabe cómo se almacenan los datos, ni el modelo sabe cómo se muestran los datos. A esto es a lo que llamamos «desacoplamiento».

Veamos la implementación:

Empezando por el modelo de datos, que representará a las entidades inmobiliarias, y haciendo uso de las herramientas que nos ofrece WordPress, lo implementaremos mediante un custom post type llamado property. Para su gestión, en la clase RealhouseProperty, implementaremos los métodos CRUD (crear, leer, actualizar y borrar).

 

Nuestro controlador RealhousePropertyController estará a la escucha de las posibles peticiones que desde la vista le puedan llegar. Interpretándolas, gestionándolas y dando respuesta, tomando como fuente de información la clase del modelo RealhouseProperty.

 

Y por último tenemos la vista, nuestro shortcode. Que en lugar de encargarse de hacer la gestión de datos y todo el proceso, simplemente se encarga de su acometido, «pintar». El shortcode hará sus peticiones al conrtrolador, sin saber en ningún momento cómo ni dónde se guardan los datos

 

Aplicándolo al desarrollo de temas

En este primer acercamiento, nos hemos centrado en la implementación del patrón de diseño en la parte de plugins. Dejaremos su implementación en los temas para más adelante.