WordPress está eliminando las barras invertidas de escape de cadenas JSON en post_meta
Pensé que estaba facilitando mi vida y siendo consciente del futuro al guardar cierto contenido como fragmentos JSON en campos post_meta personalizados. Desafortunadamente, WordPress no está de acuerdo y está haciendo mi vida increíblemente difícil.
Tengo una cadena JSON que básicamente se ve así. Esto es solo una parte, y la cadena de comentarios son solo algunas entidades unicode de ejemplo. Todo se genera con json_encode.
{
"0": {
"name": "Chris",
"url": "testdomain.com",
"comment": "\u00a5 \u00b7 \u00a3 \u00b7 \u20ac \u00b7 \u00b7 \u00a2 \u00b7 \u20a1 \u00b7 \u20a2 \u00b7 \u20a3 \u00b7 \u20a4 \u00b7 \u20a5 \u00b7 \u20a6 \u00b7 \u20a7 \u00b7 \u20a8 \u00b7 \u20a9 \u00b7 \u20aa \u00b7 \u20ab \u00b7 \u20ad \u00b7 \u20ae \u00b7 \u20af \u00b7 \u20b9"
}
}
Desafortunadamente, después de guardarlo con update_post_meta
, sale así:
{
"0": {
"name": "Chris",
"url": "testdomain.com",
"comment": "u00a5 u00b7 u00a3 u00b7 u20ac u00b7 u00b7 u00a2 u00b7 u20a1 u00b7 u20a2 u00b7 u20a3 u00b7 u20a4 u00b7 u20a5 u00b7 u20a6 u00b7 u20a7 u00b7 u20a8 u00b7 u20a9 u00b7 u20aa u00b7 u20ab u00b7 u20ad u00b7 u20ae u00b7 u20af u00b7 u20b9"
}
}
Y al eliminar las barras invertidas, no se puede hacer json_decode
para volver a convertirlo en contenido útil.
¿Alguna idea de por qué WordPress podría estar haciendo esto y si hay alguna manera de evitarlo? No puedo usar la bandera JSON_UNESCAPED_UNICODE porque esta es una instalación de PHP 5.3.x, y ya intenté codificar con htmlentities
antes de pasar el contenido a json_encode
, pero eso solo captura un pequeño subconjunto de entidades UTF-8.
¡Gracias de antemano!
(EDIT: Por cierto, sé que podría simplemente guardar un array directamente en post_meta y se serializaría y ocurriría la magia, pero me gusta la idea de tener los datos almacenados como JSON. Si no hay una solución fácil y elegante, cederé, ¡pero realmente espero que haya una solución fácil y elegante!)

¡Existe una manera elegante de manejar esto!
Pasa la cadena codificada en JSON a través de wp_slash()
. Esta función escapará la barra diagonal inicial de cada carácter Unicode codificado, lo que evitará que update_metadata()
los elimine.

Esta es una solución alternativa para un error grave de WordPress. ¡Muchas gracias!

Esta debería ser la respuesta aceptada. Tuve problemas con contenido importado desde GitHub a través de wp_insert_post donde esto era un problema importante que eliminaba barras invertidas de muestras de código. Pasar la cadena por wp_slash antes de enviarla a wp_insert_post solucionó el problema. ¡Gracias!

Esto sigue siendo útil incluso hoy, perdí horas y horas buscando una solución alternativa para esto sin ninguna pista hasta que encontré esto. Si quieres añadir esta respuesta a mi pregunta aquí: https://stackoverflow.com/questions/61091853/wordpress-breaking-unicodes-when-saving-data la marcaré como la respuesta correcta. ¡Muchísimas gracias!

¿Quién hubiera pensado que una publicación de 8 años podría ayudarme? Tenía problemas al guardar bloques serializados (Gutenberg) con atributos codificados en JSON a los que se les eliminaban las barras invertidas. Ejecutar la salida de serialize_block a través de wp_slash solucionó el problema.

Parece que no hay forma de evitarlo.
La función update_metadata(), que es finalmente responsable de guardar los metadatos, ejecuta explícitamente un stripslashes_deep() sobre el valor del meta. Esta función incluso eliminará las barras invertidas de los elementos de un arreglo, si el valor fuera un arreglo.
Hay un filtro que se ejecuta DESPUÉS de eso llamado sanitize_meta, al cual podrías engancharte. Pero en ese punto, tus barras invertidas ya han sido eliminadas, por lo que no puedes determinar de manera confiable dónde necesitaban volver a agregarse (o al menos, no sé cómo podrías distinguir entre comillas legítimas de delimitadores JSON versus partes de valores).
No puedo decir por qué hace esto, pero lo hace. Probablemente porque eventualmente se ejecuta a través de wpdb->update, que necesita las cadenas sin escapar.
Como temías, probablemente sea mejor simplemente almacenar el valor como un arreglo, que se serializará (como dijiste). Si lo quieres como JSON más tarde, puedes simplemente pasarlo por json_encode().

Tenía miedo de eso, pero es bueno saber por qué está sucediendo. ¡Muchas gracias por la rápida respuesta!

@jave.web Es cierto que no puedes evitar que update_metadata() aplique strip slashes a tu cadena. Las otras respuestas proporcionan soluciones (muy inteligentes) para esencialmente "escapar doblemente" tu cadena, de modo que el stripping inevitable elimine esas barras adicionales pero deje intactas tus barras originales. Personalmente, todavía diría que la forma "elegante" de manejar esto es simplemente almacenar los datos en un array, lo que no requiere ningún manejo especial ni pre-formateo. Luego conviértelo a json si y cuando lo necesites. Pero eso es solo mi preferencia.

Esta función realiza la transformación usando preg_replace:
function preg_replace_add_slash_json($valor) {
return preg_replace('/(u[0-9a-fA-F]{4})/i', '\\\$1', $valor);
}
Antes de cada secuencia "uXXXX" (X=0..F, hexadecimal) añade una barra invertida. Antes de enviar a la base de datos, llama a esta función.

Para cualquiera que todavía tenga problemas para guardar una cadena Unicode codificada en JSON mediante wp_update_post, lo siguiente funcionó para mí. Encontrado en class-wp-rest-posts-controller.php
// convierte el objeto de publicación en un array, de lo contrario wp_update_post esperará entrada sin escapar.
wp_update_post( wp_slash( (array) $my_post ) );
Aquí hay un ejemplo:
$objectToEncodeToJson = array(
'mi_clave_personalizada' => '<div>Aquí hay HTML que se convertirá a Unicode en la base de datos.</div>'
);
$postContent = json_encode($objectToEncodeToJson,JSON_HEX_TAG|JSON_HEX_QUOT);
$my_post = array(
'ID' => $yourPostId,
'post_content' => $postContent
);
wp_update_post( wp_slash( (array) $my_post ) );

Una forma interesante de solucionar esto es codificando en base64, como se muestra en el siguiente ejemplo.
$data = Array(0 => array('name' => 'chris' , 'URL' => "hello.com"));
$to_json = json_encode($data);
echo $to_json . "<br />";
// muestra [{"name":"chris","URL":"hello.com"}]
$to_base64 = base64_encode($to_json);
Echo $to_base64 . "<br />";
// muestra W3sibmFtZSI6ImNocmlzIiwiVVJMIjoiaGVsbG8uY29tIn1d
$back_to_json = base64_decode($to_base64);
Echo $back_to_json . "<br />";
// muestra [{"name":"chris","URL":"hello.com"}]
$back_to_aray = json_decode($back_to_json);
print_r($back_to_aray) ;
// muestra Array ( [0] => stdClass Object ( [name] => chris [URL] => hello.com ))

Sé que esta es una pregunta antigua, pero todavía es un problema que afecta a los desarrolladores hoy en día. Así que como referencia, aquí hay un buen hilo del rastreador de problemas del núcleo de WordPress que encontré informativo: https://core.trac.wordpress.org/ticket/21767

Puedes utilizar la función de WordPress stripslashes_deep().
<?php stripslashes_deep($your_json);?>
Para referencia visita aquí
