meta_query с мета значениями как сериализуемые массивы

Я работаю над проектом, в котором я создаю пользовательский тип сообщения и пользовательские данные, введенные через мета-поля, связанные с моим настраиваемым типом сообщения. По какой-то причине я решил закодировать мета-боксы таким образом, чтобы входы в каждом метаболизме были частью массива. Например, я храню долготу и широту:

  & л; р & GT;
    <метка для = "широта"> Широта: </label> <br /& gt;
    <входной тип = "текст" id = "широта" name = "координаты [широта]" class = "full-width" value = "" /& gt;
& Lt; /р & GT;
& Lt; р & GT;
    <метка для = "долгота"> Долгота: </label <br /& gt;
    <input type = "text" id = "longitude" name = "codes [longitude]" class = "full-width" value = "" /& gt;
& Lt; /р & GT;
 

По какой-то причине мне понравилась идея иметь уникальную запись postmeta для каждого метаболизма. На крюке save_post я сохраняю данные следующим образом:

  update_post_meta ($ post_id, '_координаты', $ _POST ['координат']);
 

Я сделал это, потому что у меня есть три обменных ящика, и мне нравится просто иметь 3 значения постмета для каждого сообщения; однако теперь я понял потенциальную проблему с этим. Я могу использовать WP_Query, чтобы вытаскивать определенные сообщения на основе этих метазначений. Например, я могу захотеть получить все сообщения с широтными значениями выше 50. Если бы я имел эти данные в базе данных по отдельности, возможно, используя ключ latitude , я бы сделал что-то вроде:

  $ args = array (
    'post_type' => «Мой пост-типа»,
    'meta_query' => массив (
        массив (
            'key' => «Широта»,
            'value' => '50',
            'compare' => '& GT;'
        )
    )
 );
$ query = new WP_Query ($ args);
 

Поскольку у меня есть широта как часть postmeta _coordinates , это не сработает.

Итак, мой вопрос: есть ли способ использовать meta_query для запроса сериализованного массива, подобного мне в этом сценарии?

35 голосов | спросил tollmanz 9 Mayam11 2011, 06:06:35

12 ответов


34

Нет, это невозможно.

Я настоятельно рекомендую вам неэтериализировать ваши данные и изменить вашу рутину сохранения. Нечто похожее на это должно преобразовать ваши данные в новый формат:

  $ args = array (
    'post_type' => «Мой пост-типа»,
    'meta_key' => '_координаты',
    'posts_per_page' => -1
 );
$ query = new WP_Query ($ args);
если ($ query- & GT; have_posts ()) {
    в то время как (query- $ & GT; have_posts ()) {
        $ Query- & GT; the_post ();
        $ c = get_post_meta ($ post-> id, '_ coord', true);
        add_post_meta ($ пост- & GT; ID, '_ долготы', $ C [ 'долгота']);
        add_post_meta ($ пост- & GT; ID, '_ широта', $ C [ 'широта']);
        delete_post_meta ($ пост- & GT; ID, '_ координаты', $ с);
    }
}
 

Затем вы сможете запросить, как хотите, с помощью отдельных клавиш

Если вам нужно хранить несколько долгот и несколько широт, вы можете хранить несколько метаданных с таким же именем. Просто используйте третий параметр get_post_meta , и он вернет их все как массив

Почему вы не можете запрашивать внутри сериализованных данных?

MySQL рассматривает его как просто строку и не может разбить ее на структурированные данные. Разделение его на структурированные данные - именно то, что делает код выше

Возможно, вы сможете запросить частичные куски даты, но это будет супер ненадежным, дорогостоящим, медленным и очень хрупким, с множеством краевых случаев. Сериализованные данные не предназначены для SQL-запросов и не форматируются обычным и постоянным образом.

Помимо затрат на частичные поиски строк, почтовые мета-запросы медленны, и сериализованные данные могут меняться в зависимости от таких вещей, как длина содержимого, что делает поиск невероятно дорогостоящим, если не невозможным, в зависимости от ценности, которую вы ищете

Примечание по хранению записей /объектов /объектов в качестве сериализованных объектов в метатемах

Возможно, вам захочется сохранить запись транзакции в метатете post или какой-либо другой структуре данных в метателе пользователя, а затем выполнить описанную выше проблему.

Решение здесь заключается не в том, чтобы разбить его на отдельные мета-сообщения, но для того, чтобы понять, что это не должно было быть мета для начала, а пользовательский тип сообщения. Например, журнал или запись могут быть настраиваемым типом сообщения с исходным сообщением в качестве родителя или соединены с помощью таксономического термина

ответил Tom J Nowell 20 PM00000070000004931 2012, 19:19:49
19

Я тоже сталкиваюсь с этой ситуацией. Вот что я сделал:

  $ args = array (
    'post_type' => «Мой пост-типа»,
    'meta_query' => массив (
        массив (
            'key' => «Широта»,
            'value' => sprintf (': "% s";', $ value),
            'compare' => 'КАК'
        )
    )
);
 

Надеемся на эту помощь

ответил rabni 16 PMpThu, 16 Apr 2015 15:38:57 +030038Thursday 2015, 15:38:57
10

Вы действительно потеряете возможность запрашивать свои данные любым эффективным образом при сериализации записей в базе данных WP.

Общая экономия производительности и выигрыш, которые, по вашему мнению, вы достигаете путем сериализации, не будут заметны в какой-либо значительной степени. Вы можете получить немного меньший размер базы данных, но стоимость транзакций SQL будет тяжелой, если вы когда-нибудь запросите эти поля и попытаетесь сравнить их любым полезным и значимым образом.

Вместо этого сохраните сериализацию для данных, которые вы не собираетесь запрашивать в этом виде, но вместо этого будет обращаться только пассивным способом прямым вызовом WP API get_post_meta () - от этой функции, которую вы может распаковать сериализованную запись для доступа к своим свойствам массива.

Фактически присваивается значение true , как в;

$ meta = get_post_meta ($ post-> ID, 'key', true);

Вернет данные в виде массива, доступного для вас, чтобы выполнить итерацию по нормали.

Вы можете сосредоточиться на других оптимизации базы данных /сайта, таких как кеширование, CSS и JS-минификация, и использовать такие службы, как CDN, если вам нужно. Назову лишь несколько ... WordPress Codex - хорошая отправная точка для раскрытия этой темы: ЗДЕСЬ

ответил userabuser 20 PM00000060000004231 2012, 18:36:42
2

Я только что обработал сериализованные поля и мог запросить их. Не использовать meta_query, но использовать SQL-запрос.

  global $ wpdb;

$ search = serialize ('широта'). serialize (50);

$ query = $ wpdb-> prepare ("SELECT` post_id`
FROM `wp_postmeta`
WHERE `post_id` IN (SELECT` ID` FROM `wp_posts` WHERE` post_type` = 'my-post-type')
И `meta_key` = '_координаты'
И `meta_value` LIKE '% s'", '%'. $ Search. '%');

$ ids = $ wpdb-> get_col ($ query);

$ args = array (
    'post__in' => $ иды
    'post_type' => 'team' //добавить тип, потому что по умолчанию будет 'post'
);

$ posts = get_posts ($ args);
 

Запрос сначала ищет сообщение с подходящим post_type, поэтому количество записей wp_postmeta будет меньше для фильтрации. Затем я добавил инструкцию where, чтобы уменьшить количество строк, отфильтровывая meta_key

Идентификаторы заканчиваются красиво в массиве по мере необходимости для get_posts.

PS. MySQL v5.6 или выше необходим для хорошей производительности подзапроса

ответил Tomas 22 PM00000010000004931 2013, 13:41:49
1

Этот пример действительно помог мне. Это специально для плагина S2Members (который сериализует пользовательские метаданные). Но он позволяет запрашивать часть сериализованного массива в мета-ключе.

Он работает с использованием функции REGEXP MySQL.

Здесь является источник

Вот код, который запрашивает всех пользователей, живущих в США. Я легко модифицировал его, чтобы запросить одно из моих пользовательских полей регистрации, и он работал в кратчайшие сроки.

  & lt;? php
глобальный $ wpdb;
$ users = $ wpdb-> get_results ("SELECT` user_id` как `ID` FROM` ". $ wpdb-> usermeta.
          "` WHERE 'meta_key` =' ". $ wpdb-> префикс. "s2member_custom_fields" И
           `meta_value` REGEXP '. * \" country_code \ "; s: [0-9] +: \" US \ ". *'");
if (is_array ($ users) & amp; & amp; count ($ users)> 0)
    {
        foreach ($ users as $ user)
            {
                $ user = /* Получить полный объект пользователя сейчас. * /новый WP_User ($ user-> ID);
                print_r ($ пользователю); /* Получить полный список свойств при /если отладка. * /
            }
    }
? & GT;
 
ответил BC Smith 12 WedEurope/Moscow2012-12-12T22:43:48+04:00Europe/Moscow12bEurope/MoscowWed, 12 Dec 2012 22:43:48 +0400 2012, 22:43:48
0

После прочтения кучи советов по запуску фильтрации WP_Query с помощью сериализованных массивов, вот как я в конце концов это сделал: создав массив значений, разделенных запятыми, используя implode в сочетании с $ wpdb , используя FIND_IN_SET , чтобы выполнить поиск в списке, разделенном запятыми, для запрашиваемого значения.

(это похоже на ответ Томаса, но его немного меньше производительности для SQL-запроса)

<сильный> 1. В functions.php:

В файле functions.php (или везде, где вы настраиваете мета-окно) в функция yourname_save_post () используйте

  update_post_meta ($ post-> ID, 'checkboxArray', implode (",", $ checkboxArray)); //добавление implode
 

, чтобы создать массив, содержащий значения, разделенные запятыми.

Вы также захотите изменить свою выходную переменную в функции построения метаданных yourname_post_meta () для

  $ checkboxArray = explode (",", get_post_custom ($ post-> ID) ["checkboxArray"] [0]); //добавление взрыва
 

<сильный> 2. В шаблоне PHP-файл:

Тест: если вы запустите get_post_meta ($ id); , вы увидите checkboxArray как массив, содержащий ваши значения, разделенные запятыми, а не сериализованный массив.

Теперь мы создаем наш пользовательский SQL-запрос, используя $ wpdb .

  global $ wpdb;

$ search = $ post-> ID;

$ query = "SELECT * FROM wp_posts
          WHERE FIND_IN_SET ($ search, (
              SELECT wp_postmeta.meta_value FROM wp_postmeta
              WHERE wp_postmeta.meta_key = 'blogLocations'
              И wp_postmeta.post_id = wp_posts.ID)
          )
          И (wp_posts.post_type = 'post')
          И (wp_posts.post_status = 'publish'); ";

$ posts = $ wpdb-> get_results ($ query);

foreach ($ posts as $ post) {
    //ваш почтовый контент здесь
}
 

Обратите внимание на FIND_IN_SET , вот где происходит волшебство.

Теперь ... поскольку я использую SELECT * , это возвращает все данные post и внутри foreach , вы можете повторить, что вы хотите от этого (сделайте print_r ($ posts); , если вы не знаете, что включено. Он не настроил для вас «цикл» (я так предпочитаю), но его можно легко изменить, чтобы настроить цикл, если вы предпочитаете (посмотрите в setup_postdata ($ post); в кодексе, вам, вероятно, потребуется изменить SELECT * для выбора только идентификаторов сообщений и $ wpdb-> get_results для правильного типа $ wpdb - см. код для $ wpdb ) также для информация о , который ).

Whelp, потребовалось немного усилий, но поскольку wp_query не поддерживает выполнение 'compare' => «IN» сериализованные или разделенные запятой значения, эта регулировка - ваш лучший вариант!

Надеюсь, это поможет кому-то.

ответил Gifford N. 23 Jam1000000amFri, 23 Jan 2015 01:10:32 +030015 2015, 01:10:32
0

Если вы используете оператор сравнения like в вашем мета-запросе, он должен работать нормально, чтобы просмотреть сериализованный массив.

  $ wp_user_search = новый WP_User_Query (массив (
    'meta_query' => массив (
        массив (
            'key' => 'wp_capabilities',
            'value' => 'Абонента,
            'compare' => 'не как'
            )
        )
    )
);
 

приводит к:

  [query_where] => ГДЕ 1 = 1 И (
  (wp_usermeta.meta_key = 'wp_capabilities'
  И CAST (wp_usermeta.meta_value AS CHAR) НЕ НРАВИТСЯ «% подписчика%»)
 
ответил benklocek 4 J000000Saturday15 2015, 00:14:38
0

Если мои метаданные являются типом массива, я использую этот метод для запроса по мета:

  $ args = array (
    'post_type' => «Фотобанк»,
    'posts_per_page' => -1,
    'meta_query' => массив (
            массив (
                   'key' => «коллекции»,
                   'value' => ': "'.. $ Пост- & GT; ID '";',
                   'compare' => 'КАК'
            )
     )
);
$ fotos = новый WP_Query ($ args);
 
ответил Den Media 7 J000000Thursday16 2016, 09:50:49
0

Мне было интересно узнать ответы выше, где meta_query нацелился на ключ latitude вместо _coordinates . Пришлось пойти и проверить, действительно ли это возможно в мета-запросах для таргетинга определенного ключа внутри сериализованного массива. :)

Это явно не так.

Итак, обратите внимание, что правильный ключ для цели - _coordinates вместо latitude .

  $ args = array (
     'post_type' => «Мой пост-типа»,
     'meta_query' => массив (
         массив (
             'key' => '_координаты',
             'value' => sprintf (': "% s";', $ value),
             'compare' => 'КАК'
         )
     )
 );
 

ПРИМЕЧАНИЯ:

  1. Этот подход позволяет использовать только точные соответствия. Таким образом, такие вещи, как , все широты больше 50 не возможны.

  2. Чтобы включить подстрочные совпадения, можно использовать 'value' => sprintf (': "%%% s %%";', $ value), . (не тестировались)

ответил jgangso 6 J000000Thursday17 2017, 14:57:01
0

Я думаю, что есть два решения, которые могут попытаться решить проблему сохранения результатов как String и Integer. Однако важно сказать, как отмечали другие, что гарантировать целостность результатов, хранящихся как Integer, невозможно, поскольку поскольку эти значения хранятся в виде сериализованных массивов, индекс и значения хранятся точно с одним и тем же шаблоном. Пример:

  массив (37,87);
 

хранится как сериализованный массив, например

  а: 2: {я: 0; я: 37; я: 1; я: 87;}
 

Обратите внимание на i: 0 как первую позицию массива и i: 37 в качестве первого значения. Шаблон тот же. Но перейдем к решениям


1) Решение REGEXP

Это решение работает для меня независимо от того, что мета-значение сохраняется как строка или номер /идентификатор. Однако он использует REGEXP , что не так быстро, как использование LIKE

  $ args = array (
    'post_type' => «Мой пост-типа»,
    'meta_query' => массив (
        массив (
            'key' => «Широта»,
            'value' => '\; i \:'. $ value. '\; | \ "'. $ value. '\";',
            'compare' => 'REGEXP'
        )
    )
);
 

2) LIKE Solution

Я не уверен в разнице в производительности, но это решение, которое использует LIKE , а также работает как для числа, так и для строк

  $ args = array (
        'post_type' => «Мой пост-типа»,
        'meta_query' => массив (
            'отношение' => 'ИЛИ',
            массив (
                'key' => «Широта»,
                'value' => sprintf (': "% s";', $ value),
                'compare' => 'КАК'
            ),
            массив (
                'key' => «Широта»,
                'value' => sprintf ('; i:% d;', значение $),
                'compare' => 'КАК'
            )
        )
    );
 
ответил Pablo S G Pacheco 29 MarpmThu, 29 Mar 2018 22:07:17 +03002018-03-29T22:07:17+03:0010 2018, 22:07:17
-1

Я столкнулся с чем-то подобным, используя плагин Magic Fields. Это может сделать трюк

  $ values_serialized = serialize (array ('50 '));
$ args = array (
    'post_type' => «Мой пост-типа»,
    'meta_query' => массив (
        массив (
            'key' => «Широта»,
            'value' => $ Values_serialized,
            'compare' => '& GT;'
        )
    )
);
 
ответил Seth Stevenson 13 Mayam11 2011, 01:10:32

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132