WordPress удаляет экранирующие обратные слеши из JSON строк в post_meta

25 мая 2012 г., 23:39:35
Просмотры: 15.4K
Голосов: 19

Я думал, что облегчаю себе жизнь и думаю о будущем, сохраняя некоторый контент в виде JSON в пользовательских полях post_meta. К сожалению, WordPress не согласен и делает мою жизнь невероятно сложной.

У меня есть JSON строка, которая выглядит примерно так. Это всего лишь часть, а строка комментария - просто пример юникодных символов. Вся строка генерируется с помощью 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"
    }
}

К сожалению, после сохранения с помощью update_post_meta, она выглядит так:

{
    "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"
    }
}

И со снятыми слешами, её нельзя преобразовать обратно в полезный контент с помощью json_decode.

Есть идеи, почему WordPress так делает, и можно ли этого избежать? Я не могу использовать флаг JSON_UNESCAPED_UNICODE, потому что у меня установлен PHP 5.3.x, и я уже пробовал кодировать с помощью htmlentities перед передачей в json_encode, но это захватывает только небольшую часть UTF-8 символов.

Заранее спасибо!

(ПРИМЕЧАНИЕ: Для справки, я знаю, что можно просто сохранить массив напрямую в post_meta, и он будет сериализован, и произойдет волшебство, но мне просто нравится идея хранить данные в формате JSON. Если нет простого и элегантного решения, я сдамся, но я очень надеюсь, что такое решение есть!)

0
Все ответы на вопрос 8
5
36

Есть изящный способ решить эту проблему!

Пропустите строку в формате JSON через функцию wp_slash(). Эта функция экранирует начальный слеш у каждого закодированного Unicode-символа, что предотвратит их удаление функцией update_metadata().

9 янв. 2014 г. 19:20:40
Комментарии

Это обходное решение для серьёзной ошибки в Wordpress. Огромное спасибо!

netAction netAction
7 июн. 2017 г. 10:18:55

Этот ответ должен быть принятым. У меня были проблемы с контентом, импортируемым из GitHub через wp_insert_post, где это было основной проблемой - удаление слешей в примерах кода. Пропуск строки через wp_slash перед передачей в wp_insert_post решил проблему. Спасибо!

Matt Keys Matt Keys
17 нояб. 2017 г. 21:21:05

Это решение остаётся полезным даже сегодня. Я потратил часы на поиск обходного пути без единой зацепки, пока не нашёл это. Если вы хотите добавить этот ответ на мой вопрос здесь: https://stackoverflow.com/questions/61091853/wordpress-breaking-unicodes-when-saving-data, я отмечу его как правильный ответ. Огромное вам спасибо!

Jaypee Jaypee
8 апр. 2020 г. 07:02:54

Кто бы мог подумать, что 8-летний пост сможет мне помочь. У меня были проблемы с сохранением сериализованных (Gutenberg) блоков, где JSON-закодированные атрибуты теряли свои слеши. Пропуск вывода serialize_block через wp_slash решил проблему.

Wouter van Vliet Wouter van Vliet
5 апр. 2021 г. 16:47:09

Десять лет спустя я столкнулся с той же проблемой при использовании wp_insert_post(), и это спасло мой день. Спасибо!

Saulo Padilha Saulo Padilha
11 июн. 2024 г. 01:08:23
3
11

Похоже, этого никак не избежать.

Функция update_metadata(), которая в конечном итоге отвечает за сохранение метаданных, явно применяет stripslashes_deep() к значению метаполя. Эта функция удаляет слеши даже из элементов массива, если значение является массивом.

Существует фильтр sanitize_meta, который срабатывает ПОСЛЕ этого, и в который можно добавить свой обработчик. Но к этому моменту ваши слеши уже удалены, поэтому невозможно достоверно определить, где их нужно было оставить (или, по крайней мере, я не знаю, как отличить цитирование легитимных JSON-разделителей от частей значений).

Не могу сказать, почему так сделано, но факт остается фактом. Вероятно, потому что в конечном итоге данные проходят через wpdb->update, которому нужны строки без экранирования.

Как вы и опасались, вероятно, лучше просто сохранять значение как массив, который будет сериализован (как вы и говорили). Если позже вам понадобится JSON, вы всегда можете пропустить его через json_encode().

26 мая 2012 г. 00:18:44
Комментарии

Я этого и боялся, но хорошо знать причину происходящего. Большое спасибо за быстрый ответ!

Chris Van Patten Chris Van Patten
26 мая 2012 г. 00:33:10

Это не соответствует действительности, см. другие ответы :)

jave.web jave.web
6 мар. 2015 г. 16:51:07

@jave.web Действительно, нельзя избежать того, что update_metadata() удаляет слеши из строки. Другие ответы предлагают (очень умные) обходные пути, которые по сути "двойное экранирование" строки, чтобы неизбежное удаление слешей убрало только дополнительные слеши, оставив оригинальные. Лично я считаю, что "элегантный" способ решения - просто хранить данные в массиве, который не требует специальной обработки или предварительного форматирования. Затем конвертировать в json при необходимости. Но это всего лишь моё предпочтение.

MathSmath MathSmath
6 мая 2015 г. 21:36:28
1

Вы можете обмануть WordPress с помощью чего-то подобного:

$cleandata = str_replace('\\', '\\\\', json_encode($customfield_data, true));

Это действительно простое *элегантное решение*...

1 авг. 2012 г. 13:36:28
Комментарии

+1 Это сработало в моей ситуации. Она немного отличалась от ситуации автора, но была похожей.

Adam Spriggs Adam Spriggs
1 авг. 2018 г. 14:43:16
0

Эта функция выполняет преобразование с помощью preg_replace:

function preg_replace_add_slash_json($value) {
    return preg_replace('/(u[0-9a-fA-F]{4})/i', '\\\$1', $value);
}

Перед каждой последовательностью "uXXXX" (X=0..F, шестнадцатеричный) она добавляет обратный слеш. Вызывайте эту функцию перед сохранением в базу данных.

19 янв. 2017 г. 12:04:27
0

Для тех, кто всё ещё испытывает трудности с сохранением JSON-закодированной Unicode-строки через wp_update_post, ниже приведено решение, которое сработало у меня. Найдено в class-wp-rest-posts-controller.php

// преобразуем объект записи в массив, иначе wp_update_post ожидает неэкранированные данные
wp_update_post( wp_slash( (array) $my_post ) ); 

Вот пример:

$objectToEncodeToJson = array(
  'my_custom_key' => '<div>Здесь HTML, который будет преобразован в Unicode в базе данных.</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 ) );
8 мар. 2019 г. 22:38:58
0

Интересный способ обойти это - кодирование в base64, см. пример ниже.

$data = Array(0 => array('name' => 'chris', 'URL' => "hello.com"));

$to_json = json_encode($data);

echo $to_json  . "<br />";
// выводит [{"name":"chris","URL":"hello.com"}] 

$to_base64 =  base64_encode($to_json);

Echo $to_base64 . "<br />";
// выводит W3sibmFtZSI6ImNocmlzIiwiVVJMIjoiaGVsbG8uY29tIn1d

$back_to_json =  base64_decode($to_base64);

Echo $back_to_json . "<br />";
// выводит [{"name":"chris","URL":"hello.com"}]

$back_to_aray = json_decode($back_to_json);

print_r($back_to_aray);
// выводит Array ( [0] => stdClass Object ( [name] => chris [URL] => hello.com ))
18 июн. 2013 г. 14:34:16
0

Я знаю, что это старый вопрос, но он до сих пор актуален для разработчиков. В качестве справочного материала привожу полезную ветку обсуждения из трекера проблем ядра WordPress, которая показалась мне информативной: https://core.trac.wordpress.org/ticket/21767

21 мая 2024 г. 14:54:55
1
-1

Вы можете использовать функцию WordPress stripslashes_deep().

<?php stripslashes_deep($your_json);?>

Для справки посетите эту страницу

25 янв. 2017 г. 09:49:31
Комментарии

BARBJANE's всё ещё отправляется из WordPress как BARBJANE\'s, если я ничего не упускаю здесь...

Si8 Si8
10 апр. 2018 г. 23:38:59