Contents
Introducción
Este tutorial explica paso a paso cómo implementar un sistema de favoritos en WordPress que funcione para usuarios invitados (no registrados) mediante cookies. La idea es permitir que visitantes marquen/desmarquen entradas como favoritas en su navegador. La información de favoritos se almacena en una cookie JSON en el cliente y, opcionalmente, el servidor mantiene un contador por entrada en post meta para mostrar el número total de favoritos (con las limitaciones que explico más abajo).
Requisitos y consideraciones
- WordPress (tema hijo o plugin personalizado donde puedas añadir código PHP/JS/CSS).
- Conocimientos básicos de PHP, JavaScript y cómo encolar scripts en WordPress.
- Limitaciones: una solución basada en cookies es por navegador/dispositivo. No es fiable para consenso global (varios visitantes pueden inflar contadores) y es vulnerable a manipulaciones del lado cliente. Para mejorar la integridad habría que añadir controles adicionales en servidor o exigir inicio de sesión.
Resumen del flujo
- Al renderizar cada post, el servidor lee la cookie (si existe) y marca el botón como activo si el ID del post está en la cookie.
- El visitante hace clic en el enlace Favorito (ancla). El JavaScript actualiza la cookie (añade o quita el ID) y cambia el aspecto del enlace.
- Opcional: al mismo tiempo se envía una petición AJAX al servidor para incrementar/decrementar un contador en post meta (solo para mostrar un número global, con las advertencias mencionadas).
Coloca este código en el template de tu loop (por ejemplo, single.php o content.php) o en una función que añada el enlace en los lugares deseados. El ejemplo lee la cookie wp_favorites (JSON) y marca el enlace con la clase is-active si el post está en la lista.
lt?php // Dentro del loop post_id = get_the_ID() // Leer cookie y decodificarla fav_cookie = isset(_COOKIE[wp_favorites]) ? wp_unslash( _COOKIE[wp_favorites] ) : favs = array() if ( fav_cookie ) { decoded = json_decode( fav_cookie, true ) if ( is_array( decoded ) ) { favs = array_map( intval, decoded ) } } is_fav = in_array( post_id, favs, true ) // Output: usamos un enlace porque las etiquetas button no están permitidas aquí. // data-post-id servirá para JS y para la petición AJAX. ?> data-post-id= aria-pressed=>
Paso 2 — Encolar scripts y pasar variables desde PHP a JS
En functions.php de tu tema hijo o en un plugin, encola el script de JavaScript e inyecta variables necesarias como admin-ajax.php y un nonce para seguridad.
lt?php function wpfav_enqueue_assets() { // Encola script principal (crea un archivo js/fav.js en tu tema o plugin) wp_enqueue_script( wpfav-main, get_stylesheet_directory_uri() . /js/fav.js, array( jquery ), 1.0, true ) // Localizar datos para AJAX y nonce wp_localize_script( wpfav-main, WPFavData, array( ajax_url =gt admin_url( admin-ajax.php ), nonce =gt wp_create_nonce( wp_fav_nonce ), cookieName =gt wp_favorites, cookieDays =gt 365, ) ) } add_action( wp_enqueue_scripts, wpfav_enqueue_assets )
Este script maneja los clics en los enlaces, modifica la cookie (JSON con array de IDs) y envía una petición AJAX al backend para actualizar el contador de favoritos. En el ejemplo uso jQuery por compatibilidad con WordPress.
(function(){ use strict // Helpers: leer/escribir cookie con JSON function getCookie(name) { var match = document.cookie.match(new RegExp((?:^ ) name.replace(/([.?{}()[]/ ^])/g, 1) =([^]))) return match ? decodeURIComponent(match[1]) : null } function setCookie(name, value, days) { var expires = if (days) { var date = new Date() date.setTime(date.getTime() (days2460601000)) expires = expires= date.toUTCString() } document.cookie = name = encodeURIComponent(value ) expires path=/ } function parseFavs(cookieName) { var raw = getCookie(cookieName) if (!raw) return [] try { var arr = JSON.parse(raw) if (Array.isArray(arr)) return arr.map(function(i){ return parseInt(i,10) }).filter(Boolean) } catch(e){ // cookie corrupta: limpiar return [] } return [] } function saveFavs(cookieName, arr, days) { setCookie(cookieName, JSON.stringify(arr), days) } // Toggle favorito (document).on(click, .fav-toggle, function(e){ e.preventDefault() var el = (this) var postId = parseInt(el.data(post-id), 10) if (!postId) return var cookieName = (typeof WPFavData !== undefined WPFavData.cookieName) ? WPFavData.cookieName : wp_favorites var cookieDays = (typeof WPFavData !== undefined WPFavData.cookieDays) ? parseInt(WPFavData.cookieDays,10) : 365 var favs = parseFavs(cookieName) var index = favs.indexOf(postId) var action = if (index === -1) { // añadir favs.push(postId) action = add el.addClass(is-active).attr(aria-pressed,true).text(Favorito) } else { // quitar favs.splice(index, 1) action = remove el.removeClass(is-active).attr(aria-pressed,false).text(Añadir a favoritos) } saveFavs(cookieName, favs, cookieDays) // Petición AJAX opcional para actualizar contador en el servidor if (typeof WPFavData !== undefined WPFavData.ajax_url) { .post(WPFavData.ajax_url, { action: wpfav_toggle, post_id: postId, op: action, nonce: WPFavData.nonce }, function(response){ // response handling opcional // console.log(response) }, json) } }) })(jQuery)
Paso 4 — Handler AJAX en PHP (invitados y registrados)
Este handler recibe la operación (add/remove) y actualiza un contador simple en post meta llamado _fav_count. Se registran las acciones para usuarios anónimos con wp_ajax_nopriv. Usa un nonce para evitar peticiones CSRF desde otros orígenes.
lt?php function wpfav_ajax_toggle() { // Validar nonce check_ajax_referer( wp_fav_nonce, nonce ) post_id = isset( _POST[post_id] ) ? intval( _POST[post_id] ) : 0 op = isset( _POST[op] ) ? sanitize_text_field( _POST[op] ) : if ( ! post_id ! in_array( op, array( add, remove ), true ) ) { wp_send_json_error( array( message =gt Parámetros inválidos ), 400 ) } // Obtener contador actual count = intval( get_post_meta( post_id, _fav_count, true ) ) if ( op === add ) { count } else { count = max( 0, count - 1 ) } update_post_meta( post_id, _fav_count, count ) wp_send_json_success( array( count =gt count ) ) } add_action( wp_ajax_wpfav_toggle, wpfav_ajax_toggle ) add_action( wp_ajax_nopriv_wpfav_toggle, wpfav_ajax_toggle )
Paso 5 — Estilos (CSS)
Unos estilos simples para mostrar el estado visual del favorito.
.fav-toggle { display: inline-block padding: 6px 10px background: #f2f2f2 color: #333 text-decoration: none border-radius: 4px font-size: 14px margin-right: 6px } .fav-toggle.is-active { background: #ffefef color: #d33 font-weight: bold } .fav-toggle:hover { opacity: 0.9 }
Consideraciones de seguridad y limitaciones
- Una cookie del lado cliente puede ser manipulada por el usuario. No confíes en ella para sistemas críticos.
- El contador en post meta es opcional y puede ser inflado por usuarios maliciosos (click farms, scripts automatizados). Para mitigar: añadir verificación por IP, rate-limiting o exigir inicio de sesión para afectar el contador real.
- Las cookies son por navegador/dispositivo. Si el usuario borra cookies o cambia de dispositivo, perderá la lista de favoritos.
- Si necesitas sincronización entre dispositivos, guarda la lista en user meta para usuarios logueados y haz un merge en el servidor al iniciar sesión (ej. al hacer login, enviar contenido de la cookie al servidor y fusionarlo con user meta).
Mejoras opcionales
- Persistir favoritos para usuarios registrados: al iniciar sesión, enviar la cookie al servidor y guardar en user meta (merge).
- Usar signed cookies (HMAC) o tokens para comprobar que la cookie no fue manipulada fácilmente.
- Implementar rate-limiting por IP y/o checks anti-bot para que el contador en post meta sea más confiable.
- Ofrecer una UI para ver la lista de favoritos leyendo la cookie y mostrando las entradas (usar WP REST API para obtener títulos/previews).
Checklist de archivos y dónde colocar el código
- functions.php (tema hijo) o plugin: encolar scripts (Paso 2) y handler AJAX (Paso 4).
- Template del loop (single.php / content.php): añadir el enlace de favoritos (Paso 1).
- js/fav.js: código JavaScript (Paso 3).
- css/fav.css o style.css: estilos (Paso 5).
Notas finales
Esta solución es práctica y rápida de implementar para añadir favoritos a visitantes sin registro mediante cookies. Tiene limitaciones inherentes a su naturaleza cliente-centrica para proyectos donde la integridad del dato sea crítica conviene combinarlo con almacenamiento en servidor para usuarios autenticados y medidas anti-abuso.
|
Acepto donaciones de BAT's mediante el navegador Brave 🙂 |