WordPress rimuove i backslash di escape dalle stringhe JSON in post_meta
Pensavo di semplificarmi la vita e di essere lungimirante salvando alcuni contenuti come frammenti JSON nei campi personalizzati post_meta. Sfortunatamente, WordPress non è d'accordo e sta rendendo la mia vita incredibilmente difficile.
Ho una stringa JSON che essenzialmente assomiglia a questa. Questo è solo un pezzo, e la stringa del commento è solo un insieme di entità unicode fittizie. Il tutto è generato 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"
}
}
Sfortunatamente, dopo averlo salvato con update_post_meta
, risulta così:
{
"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"
}
}
E con gli slash rimossi, non può essere json_decode
ato nuovamente in contenuto utile.
Qualche idea sul perché WordPress potrebbe comportarsi così e se esiste un modo per evitarlo? Non posso usare il flag JSON_UNESCAPED_UNICODE perché è un'installazione PHP 5.3.x, e ho già provato a codificare con htmlentities
prima che il contenuto venga passato a json_encode
, ma questo cattura solo un piccolo sottoinsieme di entità UTF-8.
Grazie in anticipo!
(EDIT: Per quel che vale, so che potrei semplicemente salvare un array direttamente in post_meta e verrebbe serializzato e accadrebbe la magia, ma mi piace l'idea di avere i dati memorizzati come JSON. Se non c'è una soluzione semplice ed elegante, mi arrenderò, ma spero davvero che ne esista una!)
C'è un modo elegante per gestire questo!
Passa la stringa codificata JSON attraverso wp_slash()
. Questa funzione eseguirà l'escape dello slash iniziale di ogni carattere unicode codificato, il che impedirà a update_metadata()
di rimuoverli.

Questa è una soluzione alternativa per un grave bug di Wordpress. Grazie mille!

Questa dovrebbe essere la risposta accettata. Ho avuto problemi con i contenuti importati da GitHub tramite wp_insert_post dove questo era un problema importante che rimuoveva gli slash dagli esempi di codice. Eseguire la stringa attraverso wp_slash prima di inviarla a wp_insert_post ha risolto il problema. Grazie!

Questo è ancora utile anche oggi, ho perso ore e ore per trovare una soluzione alternativa a questo senza un solo indizio finché non ho trovato questo. Se vuoi aggiungere questa risposta alla mia domanda qui: https://stackoverflow.com/questions/61091853/wordpress-breaking-unicodes-when-saving-data la segnerò come risposta corretta. Grazie mille!

Chi avrebbe pensato che un post di 8 anni fa potesse aiutarmi. Avevo problemi a salvare blocchi serializzati (Gutenberg), con attributi codificati in JSON a cui venivano rimossi gli slash. Eseguire l'output di serialize_block attraverso wp_slash ha risolto il problema.

Sembra non ci sia modo di evitarlo.
La funzione update_metadata(), che è fondamentalmente responsabile per il salvataggio dei meta, esegue esplicitamente stripslashes_deep() sul valore del meta. Questa funzione rimuoverà anche gli slash dagli elementi degli array, se il valore fosse un array.
C'è un filtro che viene eseguito DOPO chiamato sanitize_meta, al quale potresti agganciarti. Ma a quel punto, i tuoi slash sono già stati rimossi, quindi non puoi determinare in modo affidabile dove dovevano essere reinseriti (o almeno, non so come potresti distinguere tra la citazione di delimitatori JSON legittimi e parti di valori).
Non posso dire perché lo faccia, ma lo fa. Probabilmente perché alla fine viene eseguito tramite wpdb->update, che ha bisogno delle stringhe senza escape.
Come temevi, probabilmente è meglio memorizzare il valore come un array, che verrà serializzato (come hai detto). Se lo vuoi come JSON in seguito, puoi semplicemente eseguirlo tramite json_encode().

Avevo paura di questo, ma è bene sapere perché succede. Grazie mille per la risposta rapida!

@jave.web È vero che non puoi evitare che update_metadata() esegua strip slashes sulla tua stringa. Le altre risposte forniscono soluzioni alternative (molto intelligenti) per "doppiamente escape" la tua stringa, in modo che la rimozione inevitabile degli slash rimuova quelli aggiuntivi ma lasci intatti i tuoi slash originali. Personalmente direi ancora che il modo "elegante" per gestire questo è semplicemente memorizzare i dati in un array, che non richiede alcuna gestione speciale o pre-formattazione. Poi convertilo in json se e quando necessario. Ma questa è solo la mia preferenza.

Questa funzione esegue la trasformazione utilizzando preg_replace:
function preg_replace_add_slash_json($value) {
return preg_replace('/(u[0-9a-fA-F]{4})/i', '\\\$1', $value);
}
Prima di ogni sequenza "uXXXX" (dove X=0..F, esadecimale) aggiunge un backslash. Chiama questa funzione prima di inviare i dati al database.

Per chiunque abbia ancora difficoltà a salvare una stringa Unicode codificata in JSON tramite wp_update_post, quanto segue ha funzionato per me. Trovato in class-wp-rest-posts-controller.php
// converte l'oggetto post in un array, altrimenti wp_update_post si aspetterà un input non escapato.
wp_update_post( wp_slash( (array) $my_post ) );
Ecco un esempio:
$objectToEncodeToJson = array(
'my_custom_key' => '<div>Ecco del HTML che verrà convertito in Unicode nel database.</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 ) );

Un modo interessante per aggirare questo problema è codificare in base64, vedi l'esempio qui sotto.
$data = Array(0 => array('name' => 'chris' , 'URL' => "hello.com"));
$to_json = json_encode($data);
echo $to_json . "<br />";
//stampa [{"name":"chris","URL":"hello.com"}]
$to_base64 = base64_encode($to_json);
Echo $to_base64 . "<br />";
//stampa W3sibmFtZSI6ImNocmlzIiwiVVJMIjoiaGVsbG8uY29tIn1d
$back_to_json = base64_decode($to_base64);
Echo $back_to_json . "<br />";
//stampa [{"name":"chris","URL":"hello.com"}]
$back_to_aray = json_decode($back_to_json);
print_r($back_to_aray) ;
//stampa Array ( [0] => stdClass Object ( [name] => chris [URL] => hello.com ))

So che questa è una domanda vecchia, ma è ancora un problema che colpisce gli sviluppatori oggi. Quindi come riferimento, ecco una buona discussione dal tracker dei problemi del core di WordPress che ho trovato informativa: https://core.trac.wordpress.org/ticket/21767

Puoi utilizzare la funzione WordPress stripslashes_deep().
<?php stripslashes_deep($your_json);?>
Per riferimento visita qui
