WPCS
Un conmutador de divisas para sitios WordPress sin WooCommerce: los precios escritos en el contenido se convierten a la divisa del visitante.
- Primera versión
- Instalaciones activas
- 900+
- Valoración
- Leer reseñas
Sobre mí
WPCS lleva el cambio de divisas de WOOCS a sitios WordPress corrientes: operadores turísticos, listados inmobiliarios, listas de precios de servicios. Los precios se escriben en una divisa base mediante el shortcode [wpcs_price] o un campo post meta y se muestran en la divisa que eligió el visitante o en la asignada a su país.
Sin WooCommerce, el plugin carece de toda la infraestructura habitual: no hay filtros de precios, ni gestor de sesiones, ni servicio de geolocalización. Tiene que recordar por su cuenta la elección del visitante, obtener tasas de cambio de fuentes externas que cambian o desaparecen, y seguir funcionando detrás de cachés de página completa que sirven el mismo HTML a todos.
La respuesta es una única cadena de proceso de precios (tasa, precisión, separadores, plantilla de símbolo), almacenamiento intercambiable por visitante, proveedores de tasas que devuelven una tasa o un error en lugar de un cero, y un modo de caché en el que los precios se emiten como spans etiquetados y se vuelven a renderizar para cada visitante mediante una única llamada AJAX.
La versión premium y la versión gratuita de wordpress.org comparten una misma base de código; la versión gratuita está limitada a dos divisas.
WPCS · selector de moneda
qué se resolvió
Conversión y formato de precios
shipped · 2016Qué aportaLos visitantes ven los precios en su divisa con el símbolo y los decimales correctos. Los propietarios pueden añadir un margen a las tasas o fijar precios por divisa.
- Problema
- Los precios de las entradas se escriben en una divisa base. Cada visitante debe verlos convertidos con la tasa, la precisión, los separadores y la posición del símbolo correctos, sin las funciones de precios de WooCommerce.
- Solución
Todos los precios pasan por una única cadena de proceso: multiplicar por la tasa, formatear con la precisión y los separadores de cada divisa, y envolver en una plantilla de símbolo y un span etiquetado que conserva el importe base.
- Stack
El contenido solo contiene precios en la divisa base[wpcs_price] convierte un valor literal o un campo post meta con la tasa actual
El shortcode acepta value, o meta_value con un post_id opcional; post_id sin meta_value lee la clave meta wpcs_price. price() multiplica por la tasa solo cuando la divisa actual difiere de la base, y luego pasa el número a format_price_numeric() y al filtro wpcs_price.
price_html() envuelve el resultado en un span con un ID único y data-amount con el valor base, que el modo de caché de página usa más tarde para volver a renderizarlo.
Algunos precios no deben seguir la tasa de cambiotype="fixed" acepta importes por divisa como 'USD:15,EUR:20'
Para los precios fijos, el shortcode analiza la lista y la convierte en un mapa y muestra el importe de la divisa actual, o 'none' si falta. La lista de precio en todas las divisas usa el mismo mapa en lugar de convertir.
Las divisas difieren en céntimos, decimales y separadoresPrecisión a partir de una lista de divisas sin céntimos y decimales por divisa; separadores por divisa
JPY y TWD se muestran siempre sin céntimos; cualquier divisa puede añadirse a esa lista con hide_cents. Los ajustes incluyen decimales por divisa y separadores decimal y de miles por divisa. La elección del separador es un índice en dos arrays paralelos, donde el índice 0 significa el ajuste global, de modo que los sitios existentes conservan su formato.
Los sitios quieren un margen sobre la tasa de mercado'Interest' por divisa que se suma a la tasa al leerla; la página de ajustes ve la tasa en bruto
El interest es un importe fijo guardado junto a la tasa. get_currencies() lo suma a la tasa en todas partes salvo en la página de ajustes del plugin, de modo que el administrador edita la tasa limpia mientras que el front end convierte con la ajustada. Después se ejecuta un filtro wpcs_currency_data_manipulation para reglas personalizadas.
Mostrar un precio en todas las divisas y convertir entre dos cualesquieraEl precio formateado se vuelve a convertir a la base y luego se convierte hacia delante; tasa cruzada to/from
La lista de información de precios quita el separador de miles de la cadena ya formateada, normaliza el separador decimal, convierte de nuevo a la base con back_convert() (1/rate) y luego hacia delante a cada una de las demás divisas. El endpoint de [wpcs_converter] usa rate[to] / rate[from], ambas relativas a la base, y elimina los céntimos en las divisas sin céntimos.
A veces un precio debe mostrarse en una divisa para todos los visitantesfix_currency cambia la divisa actual para un precio convertido y luego la restaura
Para un precio convertido, el shortcode recuerda la divisa del visitante, cambia a la solicitada si está configurada, renderiza y vuelve a cambiar, de modo que el resto de la página conserva la elección del visitante.
Fuentes de tasas de cambio y actualizaciones
shipped · 2016Qué aportaLas tasas de cambio se actualizan por sí solas desde varias fuentes, y una actualización fallida nunca convierte un precio en cero.
- Problema
- Las API de tasas gratuitas cambian, se cierran o empiezan a exigir claves; los bancos nacionales publican tasas solo frente a su propia divisa; y una consulta fallida no debe sustituir una tasa que funciona por cero.
- Solución
Cada fuente es un proveedor que devuelve una tasa relativa a la divisa base del sitio o -1 con un mensaje de error; WP-Cron actualiza las tasas y guarda solo valores superiores a cero.
- Stack
Las API de tasas aparecen, cambian y se cierranProveedores resueltos por nombre; los nombres desconocidos van a un filtro para fuentes personalizadas
El changelog refleja esa rotación: Yahoo eliminado en 1.1.1 (2017), Google eliminado en 1.1.2 (2018), ambos añadidos de nuevo en 1.1.3 (2018), fuentes que dejaron de funcionar eliminadas otra vez en 1.1.3 y 1.1.4, agregadores personalizados mediante un hook en 1.1.5 (2020). Cada fuente es una clase con getApiUrl() y parseResponse() sobre una base compartida RateProvider.
get_rate_provider() asigna el valor de la opción a un nombre de clase; si no existe la clase, wpcs_add_aggregator_processor permite a un sitio conectar su propia fuente, y wpcs_announce_aggregator la añade a la lista de ajustes. La lista de ajustes tiene 14 fuentes.
Los bancos centrales cotizan cada divisa frente a la suyaTasas cruzadas calculadas como rate[to] / rate[base] cuando la base del sitio es distinta
El BCE publica frente a EUR, el Banco Nacional de Ucrania frente a UAH y el Magyar Nemzeti Bank frente a HUF. Cada proveedor gestiona tres casos: la base es la divisa del banco, el destino es la divisa del banco, ninguno de los dos. La fuente MNB es un servicio SOAP con comas decimales y cotizaciones por unidad (por ejemplo 100 JPY), que se normalizan antes de dividir.
Una consulta fallida no debe fijar una tasa de ceroLos proveedores devuelven -1 con un error; cron guarda solo tasas mayores que cero
get_rate() devuelve el texto de error del proveedor en lugar de un número cuando la tasa es negativa. rate_auto_update() convierte los resultados a float y sustituye una tasa solo cuando el nuevo valor es superior a cero, de modo que una fuente rota nunca escribe cero ni un texto de error como tasa.
Las tasas deben actualizarse sin que un administrador abra los ajustesEvento de WP-Cron con los intervalos añadidos 'week' y 'month'
Los ajustes ofrecen cada hora, dos veces al día, diario, semanal o mensual. El plugin registra los dos intervalos adicionales mediante cron_schedules y programa el evento con el intervalo seleccionado al cargar, cuando todavía no está programado.
Cambiar la divisa base invalida todas las tasas guardadassave_etalon() marca la nueva base y vuelve a consultar todas las tasas frente a ella
El manejador AJAX guarda la nueva bandera is_etalon, establece en memoria la nueva divisa por defecto, solicita una tasa para cada una de las demás divisas mediante el proveedor activo y devuelve las tasas al formulario de ajustes.
Configurar muchas divisas a mano es lento y propenso a erroresTabla integrada de 118 divisas; el alta masiva obtiene tasa y bandera (interfaz premium)
WPCS_World_Currencies guarda el símbolo, la descripción, los decimales y el código de bandera de cada divisa. add_currencies_ajax() añade las seleccionadas, obtiene una tasa para cada una, registra los símbolos desconocidos como signos personalizados y descarga la bandera en la biblioteca de medios, recurriendo a una URL remota de la bandera si la descarga falla. El diálogo de alta masiva solo se muestra en la versión premium.
Divisa del visitante y caché de páginas
shipped · 2016Qué aportaCada visitante conserva su divisa elegida incluso en páginas en caché, de modo que el sitio puede seguir siendo rápido sin mostrar la divisa de otra persona.
- Problema
- La divisa elegida pertenece a un visitante, pero las cachés de página completa sirven el mismo HTML a todos, y el almacenamiento indexado por IP mezcla a los visitantes detrás de un mismo proxy o NAT.
- Solución
Almacenamiento intercambiable por visitante, y un modo de caché en el que el navegador pide a admin-ajax que vuelva a renderizar todos los spans de precio de una página en caché para la divisa del visitante.
- Stack
El HTML en caché muestra la divisa de quien calentó la cachéModo caché: el JS recopila todos los spans .wpcs_price y los vuelve a renderizar en una sola petición
Cada span de precio lleva un ID único y el importe base. Con la opción de caché activada, front.js envía los pares id/importe a wpcs_get_prices_html, que resuelve la divisa del visitante en el servidor y devuelve un mapa de id a nuevo HTML más la divisa actual; después los widgets del conmutador se sincronizan con ella. El modo está presente en el código de 2016.
Mientras los widgets del conmutador se ajustan a la divisa devuelta, una bandera impide que sus eventos change inicien otro cambio de divisa.
Los hostings difieren en qué almacenamiento por visitante funcionaEstrategia de almacenamiento elegida en los ajustes: sesión, transient indexado por IP o cookie
WPCS_STORAGE construye el backend por nombre a partir de una clase abstracta Storage. SessionStorage::create() devuelve false cuando session_start() falla, y el wrapper recurre entonces al almacenamiento en transients. Todo valor se sanea al escribirse.
Los visitantes detrás de una misma IP no deben compartir una divisa elegidaAlmacenamiento por cookie: UUID aleatorio en una cookie, valores en transients
El changelog nombra la razón: los transients indexados por IP mezclan a los usuarios que comparten dirección. CookieStorage indexa los transients por una cookie UUID. Si las cabeceras ya se han enviado cuando se crea el ID, imprime un script en el pie que envía el ID a un endpoint AJAX con comprobación de nonce, el cual establece la cookie desde una respuesta limpia.
?currency= en los enlaces divide las cachés y se filtra a las URL compartidasModo opcional: establecer la divisa por AJAX y recargar, sin parámetro GET
En el modo por defecto, wpcs_redirect() reconstruye la URL actual conservando los demás parámetros GET y el #ancla. En el modo 'No GET data in link', envía la divisa a wpcs_set_currency_ajax y recarga. Los parámetros GET reflejados en el script de la página se sanean antes de forma recursiva.
La divisa de bienvenida o geográfica debe aplicarse una vez, sin anular una elecciónBandera de primera visita en el almacenamiento; la lógica de divisa por defecto solo se ejecuta mientras vale 0
En la primera petición se guarda la divisa de bienvenida y se establece la bandera; las reglas geográficas también se ejecutan solo en una primera visita única. Si más tarde se elimina de la lista una divisa guardada, get_currencies() recurre a la base.
Selección de divisa por Geo-IP
shipped · 2017Qué aportaLos visitantes nuevos ven automáticamente la divisa de su país, según las reglas que define el propietario, sin pagar un servicio de localización.
- Problema
- Sin WooCommerce no hay servicio de geolocalización, así que el plugin debe asociar la IP de un visitante a un país en cualquier hosting, detrás de proxies y CDN, sin una API de pago.
- Solución
Una base de datos de países de MaxMind incluida, detrás de una interfaz de resolución, con una base de datos GeoIP2 opcional que descarga el propietario del sitio, y reglas de administración que asocian países con divisas.
- Stack
Detección de país en un sitio sin WooCommerceMaxMind GeoIP.dat incluido con su lector PHP
WC_Geolocation de WooCommerce no está disponible en un sitio WordPress simple, así que el plugin incluye su propia base de datos de países. lib/GeoIP.dat y geoip.inc se envuelven en OpenIpCountryResolver con una caché por IP en cada petición.
La IP real del cliente queda oculta detrás de proxies y CDNLeer X-Real-IP, luego el primer salto de X-Forwarded-For y después REMOTE_ADDR
Con la base de datos incluida, la cabecera HTTP_CF_IPCOUNTRY de Cloudflare se usa directamente y se omite la consulta a la base de datos. Una petición cuyo REMOTE_ADDR es 127.0.0.1 o ::1 se resuelve como 8.8.8.8 antes de leer las cabeceras de proxy.
Los datos de países heredados son menos precisosOpción GeoIP2: GeoLite2 .mmdb descargado y descomprimido en administración
Con una clave de licencia de MaxMind, el administrador descarga el archivo GeoLite2-Country; el manejador descomprime el .tar.gz con PharData, localiza el archivo .mmdb, lo copia a uploads/currency-switcher y elimina los archivos temporales tanto si tiene éxito como si hay error. Sin clave, el plugin se queda con la base de datos incluida. Las consultas pasan por el paquete de Composer geoip2.
Asociar países con divisas, con una sobrescritura a nivel de códigoReglas divisa => países; el filtro wpcs_geo_position sobrescribe el país
init_geo_currency() resuelve el país, lo pasa por wpcs_geo_position, lo guarda para el visitante y aplica la primera regla coincidente solo en una primera visita. [wpcs_check_country] imprime el país detectado para depurar una regla.
Refuerzo de las entradas públicas
shipped · 2021Qué aportaLos visitantes anónimos no pueden abusar del conmutador de divisas para inyectar contenido ni cambiar ajustes, de modo que los precios y las páginas se mantienen como los dejó el propietario.
- Problema
- El conmutador se ejecuta en cada página del front end, expone endpoints AJAX a visitantes anónimos y toma atributos de shortcode de los autores, de modo que datos externos llegan al HTML, al almacenamiento y a los ajustes.
- Solución
Comprobar los códigos de divisa de la URL y del formulario del conmutador frente a la lista configurada, limitar y validar por patrón los arrays de la petición, escapar los atributos y codificar el JSON para un contexto HTML.
- Stack
El endpoint público de precios recibe un array de visitantes anónimosMáx. 500 elementos, comprobación de patrón del id, comprobaciones de escalares, salida con JSON_HEX_*
wpcs_get_prices_html está disponible para visitantes anónimos. Recorta la entrada a 500 elementos, acepta solo ids que coincidan con el juego de caracteres de uniqid() que usa price_html(), omite precios no escalares y codifica la respuesta con JSON_HEX_TAG, AMP, APOS y QUOT porque admin-ajax la sirve como text/html.
Los valores del shortcode acaban en atributos de datos HTMLAtributos data-* construidos con esc_attr() en clave y valor
price_html() escribe en atributos data-* del span de precio valores que proceden de los atributos de [wpcs_price], como el importe base o la lista en bruto 'USD:15,EUR:20' de un precio fijo. Las claves y los valores se escapan y se entrecomillan, de modo que un valor de atributo no puede inyectar marcado.
El endpoint de tasas construye una cadena de shortcode a partir de la entrada de la peticiónLista de exclusión intersecada con los códigos conocidos, divisa validada, precisión con intval
wpcs_rates_current_currency pasa la entrada del visitante a do_shortcode(). Solo sobreviven los códigos de divisa que existen en la configuración, el resultado pasa por esc_attr y la precisión se convierte a int, de modo que no se puede inyectar sintaxis adicional de shortcode.
Una divisa de la URL o del formulario del conmutador puede ser cualquier cadenaValores de URL y formulario aceptados solo si son códigos configurados; valores guardados saneados
El campo del formulario del conmutador de divisas y el parámetro ?currency= se comprueban con array_key_exists() frente a la lista configurada antes de llegar al almacenamiento, y WPCS_STORAGE::set_val() sanea cada valor.
Los símbolos con entidades HTML se rompían en los ciclos de ida y vuelta del formulario de ajustesSímbolos enviados como hashes md5 y asignados de nuevo a la lista de símbolos conocidos
Símbolos como руб. se guardan como entidades. El select envía md5(symbol), y el manejador de guardado asigna el hash de vuelta a la entidad original de la lista conocida, de modo que la entidad ni se codifica dos veces ni se toma de la entrada en bruto. El guardado está protegido con check_admin_referer(), y position se comprueba frente a una lista fija.
Cifras
wordpress.org- Instalaciones activas 900+ contador de wordpress.org.
- Reseñas 13 Media de 4.1 sobre 5.
- Años de soporte 10 Desde 26 de mayo de 2016, última actualización 21 de septiembre de 2026.