Как создать новые колонки таблицы в базе данных? Или использовать массив в метаданных поста
Создаю плагин WordPress, который после активации должен к стандартной таблице wp_posts добавить две колонки positive_users_reaction и negative_users_reaction. В ячейках этих колонок хочу складывать id пользователей которые положительно/негативно оценили каждый пост. Вот код.
function create_rows()
{
global $wpdb;
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
$table_name = $wpdb->get_blog_prefix() . 'posts';
$charset_collate = $wpdb->get_charset_collate();
$sql = "ALTER TABLE {$table_name}
(ADD COLUMN
positive_users_reaction TEXT NOT NULL AFTER comment_count,
negative_users_reaction TEXT NOT NULL AFTER positive_users_reaction);
{$charset_collate}";
dbDelta($sql);
$wpdb->insert(
$table_name,
array(
'positive_users_reaction' => [],
'negative_users_reaction' => [],
)
);
}
create_rows();
Подскажите, почему оно ничего не создает и не назначает скобки объекта по умолчанию (Ведь это же правильный стартовый шаблон если надо получать array? Как это поправить что б создавало две колонки?
dbDelta() не работает с ALTER TABLE. Используй $wpdb->query(). Ну и как в комментах ниже написали, лучше метаполя юзать. Не надо родные таблицы ВП использовать для этого, кроме случаев когда вы 100% знаете и понимаете зачем вам именно так нужно.
Вместо {$table_name} должно быть ${table_name}.
Со второй переменной аналогично.
Это не помогло. Да и в документациях оно так пишется
Вам надо делать без затрагивания таблицы, на самом дела это странный подход.
Вместо колонок, вам надо смотреть в сторону метаполей.
https://wp-kama.ru/function/update_post_meta
Это PHP, не JS
Оказывается можно и так и так...
Не помню чтобы видел, что где-то в PHP так писали
${table_name}.Странно, но я наоборот запомнил именно такой вид написания как в шаблонизации JS.
Мало того, оно даже в редакторах правильно подсвчивается.
Спасибо за совет. Так
static function activation() { function create_rows() { global $wpdb; require_once ABSPATH . 'wp-admin/includes/upgrade.php'; $table_name = $wpdb->get_blog_prefix() . 'posts'; $charset_collate = $wpdb->get_charset_collate(); $wpdb->query("ALTER TABLE ${table_name} ADD COLUMN positive_users_reaction TEXT NOT NULL AFTER comment_count"); $wpdb->query("ALTER TABLE ${table_name} ADD COLUMN negative_users_reaction TEXT NOT NULL AFTER positive_users_reaction"); } create_rows(); flush_rewrite_rules(); }Код работает. Можете ещё помочь с второй частью вопроса - Хочу что б изначально в ячейках колонок хранился как-бы шаблон, который указывал что это массивы из значений. Но вот такой код
function create_rows() { global $wpdb; require_once ABSPATH . 'wp-admin/includes/upgrade.php'; $table_name = $wpdb->get_blog_prefix() . 'posts'; $charset_collate = $wpdb->get_charset_collate(); $wpdb->query("ALTER TABLE ${table_name} ADD COLUMN positive_users_reaction TEXT NOT NULL AFTER comment_count"); $wpdb->query("ALTER TABLE ${table_name} ADD COLUMN negative_users_reaction TEXT NOT NULL AFTER positive_users_reaction"); $wpdb->insert( $table_name, array( 'positive_users_reaction' => '[]', 'negative_users_reaction' => '[]', ) ); } create_rows();Не создает некое представление для ячеек. Не могу найти пример где б в mySQL говорилось про хранение массивов в ячейках таблицы базы.
В mySQL нет массивов - есть строки, который могут содержать JSON. Чтобы по умолчанию они там хранились надо в описании колонки указать DEFAULT, как-то так.
ALTER TABLE ${table_name} ADD COLUMN positive_users_reaction TEXT NOT NULL DEFAULT '[]' AFTER comment_countДалее в коде всегда обрабатываешь эти значения строк через json_encode() (для записи значения) json_decode() (для получения).
$wpdb->insert() тут вообще не подходит!
ПС: Ну и как писалось выше и учитывая что у вас такие вопросы. Все же лучше хранить это в метаполях...
Спасибо, большое. Не очень понимаю, как в метаполях держать массивы и ещё и работать с ними. С документации понял, что там работают с обычными переменными. Ещё, был бы благодарен если бы объяснили почему так сильно все рекомендуют не трогать стандартные таблицы WP? Кроме вопросов безопасности там есть какие-то опасности?
Потому что в этих таблицах храняться данные меню, других плагинов, типов записей, которые могут не оносится к вашей users_reaction логике. Потому что у этих таблиц есть задокументировання структура, с которой работают и другие плагини и черт знает кто и как может их использовать. Добавление новых полей туда может где-то чтото сломать или может быть какой-то конфликт который сломает работат вашего кода или кода другого плагина. В будущем ВП теоретически может запретить добавлять в эту таблицу свои колонки. Вообще может быть что угодно.
С другой стороны, для любых дополнительных данных записей в WP предусмотрены метаполя, которые также задокументированы и имеют своюлогику, кэшируются и т.д. По сути у вас нет ни одной причины хранить данные массива в основной таблице, а не в таблице метаполей. Вам в любом случае придется с ними работать и писать какой-то кастом под них, и делать это все равно где - в метаполях или для основной таблицы. Так зачем совать данные не туда где для них специально приготовлено место?
Чтобы менять привычную структуру движка, вам нужна веская причина, какая она у вас? просто так хочется? Это не причина - это просто ваше желание не подкрепленное никакой логикой.
В БД вообще нельзя хранить массивы. Там есть только строки и массивы храняться там в виде сериализоыванной, JSON, какой-то вашей кастомной строки, которая при получении парсится и превращается в массив.
Прочитай как работают функции update_post_meta() и get_post_meta(). В значения можно указывать массив и он будет храниться в серриализованном виде в БД. Как вариант можно вручную сохранять туда JSON и работать с ним.
Тут главный вопрос как вообще тебе придется работать с данными, просто сохранять их и потом считывать где нужно - 100% метаполя. Если нужна будет сортировка или выборка по отдельным полям из этого массива, то эти поля нужно сохранять как отдельные метаполя и потом делать сотировку по отедльным метаполям.
Спасибо, за объяснения. С update_post_meta() как-то понятнее не стало. Это получается Надо будет каждый раз получать данные $str=get_post_meta(), потом превращать их в массив str_split($str) добавлять/отнимать значения из этого массива, а потом снова превращать в строку и возвращать в это метополе? Или есть какое-то решение попроще ?
function addRatingForPost(){ $postId = $_POST['postId']; // ID поста $currentUserId = $_POST['currentUserId']; // ID пользователя которому понравился пост $prevData = get_post_custom_values( 'positive_users_reaction', $postId, true ); if( empty( $prevData ) ) { update_post_meta($postId, 'positive_users_reaction', '[]'); } $prev = str_split($prevData); $newData = array_push($prev, $currentUserId); $n2 = implode(",", $newData); update_post_meta($postId, 'positive_users_reaction', $n2, $prevData); wp_die(); }Этот код чего-то не отрабатывает. Отдает 500
function addRatingForPost() { if( empty( $_POST['postId'] ) || !isset( $_POST['currentUserId'] ) ) wp_send_json( ['error' => __( 'Wrong Data' )] ); $postId = (int)$_POST['postId']; // ID поста $currentUserId = (int)$_POST['currentUserId']; // ID пользователя которому понравился пост $data = !empty( get_post_meta( 'positive_users_reaction', $postId, true ) ) ? get_post_meta( 'positive_users_reaction', $postId, true ) : []; if( !in_array( $currentUserId, $data ) ) $data[] = $currentUserId; update_post_meta( $postId, 'positive_users_reaction', $data ); wp_die(); }Как то так, и в PHP не принято писать верблюжьей нотацией.
Спасибо, буду знать. Как-то не так скрипт обновляет.

При нажатии кнопки новым пользователем идет перезапись параметров, а необходимо дополнение массива данных. Тут явно должно задействоваться значение $prev_value из update_post_meta. Не очень понимаю, как он работает ваша строка
if (!in_array($currentUserId, $data)) $data[] = $currentUserId;
думал, что в meta_value будут храниться значения по типу {1,5,2}
Не понимаю, что тут сложного-то? Ну, потыкай чуть посмотри как работает, я вообще уже молчу что в описании функций есть примеры все которые тебе могут пригодится.
Есть две функции get_post_meta() и update_post_meta(). Одна получает, другая сохраняет что ей дали. Все!
Остальное - твоя логика - как напишешь так и будет работать. Нужно дополнять данные? Так получи то что есть сперва, добавь туда что надо и сохрани что получилось.
$data = get_post_meta( $post_id, 'meta_key', true ); if( ! $data ){ $data = []; } $data[] = 'new el'; update_post_meta( $post_id, 'meta_key', $data );Обе функции понимаю если в значении массив (он сериализуется/десереализуется при сохранении/получении). Если нужно не сериализовать, а хранить как JSON, например, то пиши конвертацию туда и обратно отдельно (из коробки эти функции сереализуют массивы, а не в JSON строку первращают их).
Такое впечатление, что не понимаете задачу. Ваш пример не чувствительн к тому, что уже было записано в ячейке (То что я ищу)... Аналогичен тому, что написал el-lable
При вызове вы каждый раз перезаписываете новыми данными, не обращая внимания на то, что там хранилось... Параметр $prev_value из документации не фигурирует. Пример. Вот в 'meta_key' ячейке хранилось значение (ID пользователя поставившего лайк), дальше мы вешаем срабатывания приведенного скрипта на какую-то кнопку. И в вашем случаи в ячейке базы будет храниться значение ID последнего пользователя поставившего лайк. А не всех
PS там что-то с приведением типов не так.
это так не сработает.
если вам нужно знать кто последний совершил некое действо(лайк или дизлайк)
поменяйте эту строку в моем примере с
на
if( !in_array( $currentUserId, $data ) ) { $key = array_search( $currentUserId, $data ); unset( $data[$key] ); } $data[] = $currentUserId;При таком варианте $currentUserId у вас будет всегда последним в масиве, и это всегда позволит получать вам последнего пользователя, если он был конечно, из него(массива)
нет, это не то что необходимо. el-lable скрипт который вы описали работает так -> заходит пользователь (id=1) на страницу читает пост, жмет кнопку Понравилось в базу в ячейку пишется вот такое a:1:{i:0;i:1;} Приходит следующий пользователь (id=2) на ту же страницу, читает пост, нажимает кнопку Понравилось теперь в ячейке базы находиться a:1:{i:0;i:2;} так оно отображает... Так понятно ? А по хорошему после второго пользователя там должно было быть [1,2] (ну или ассоциативный массив, не важно) после третьего [1,2,3] где цифры - id пользователей которые нажали кнопку Понравиться.
Какая вам хрен разница что по факту хранится в ячейке таблицы БД?
Вы получаете данные get_post_meta() - в виде массива, и записываете их с помощью update_post_meta() тоже массивом, ничего с данными при передачи-получении конвертировать или как-то преобразовывать не нужно, эти матоды это делают сами.
И в каком формате хранятся данные в ячейке таблицы, сериализованные или в виде json, да хоть в XML-е - на кой ляд вам это нужно?
Конечно чувствителен, еще раз тот же пример с комментариями в которых видно где и как он чувствителен:
// Получаем что сейчас хранится в БД, в метаполе 'meta_key' $data = get_post_meta( $post_id, 'meta_key', true ); // Если сейчас хранится ничего (поля нет или там пустая строка), // то укажем что данные - это пустой массив. if( ! $data ){ $data = []; } // ДОБАВЛЯЕМ нового пользователя в массив! // ВНИМАНИЕ не перезаписываем что там было до этого, а добавляем к тому что было! $data[] = get_current_user_id(); // Сохраняем весь массив (с тем что там было и что мы добавили) update_post_meta( $post_id, 'meta_key', $data );Спасибо за объяснение строчек кода. Вопросы всё же остались. После первого захода, в ячейку массива записало
a:1:{i:0;i:1;} после второго пользователя с другим ID в ячейке уже было - a:2:{i:0;i:1;i:1;i:4;} после третьего пользователя a:3:{i:0;i:1;i:1;i:4;i:2;i:3;} Может чего не понимаю, но это не очень похоже на стандартные объект php... ключ-значения по разным элементам. Это такая особенность WordPress? Не понимаю как это отфильтровывать. Допустим, что б один и тот же пользователь не имел возможность добавить ID в массив больше одного раза.
Ага, всё дошло сериализованый массив. Уникальные значения через $data = array_unique( $data ); Ещё раз всем спасибо.