Я был дни над этой проблемой сейчас. Первоначально это было, как хранить данные о подписчиках пользователя в базе данных, для чего я получил пару хороших рекомендаций здесь, на WordPress Ответы. После, следуя рекомендациям, я добавил новую таблицу, подобную этой:
id leader_id follower_id
1 2 4
2 3 10
3 2 10
В приведенной выше таблице в первой строке указан пользователь с идентификатором 2, за которым следует пользователь с идентификатором 4. Во второй строке за пользователем с идентификатором 3 следует пользователь с идентификатором. из 10. Та же логика применяется для третьего ряда.
Теперь, по сути, я хочу расширить WP_Query, чтобы я мог ограничить количество сообщений, извлекаемых сообщениями только лидера (ов) пользователя. Таким образом, принимая во внимание приведенную выше таблицу, если бы я передал идентификатор пользователя 10 в WP_Query, результаты должны содержать только сообщения с идентификатором пользователя 2 и идентификатором пользователя 3.
Я много искал, пытаясь найти ответ. Также я не видел ни одного учебника, который бы помог мне понять, как расширить класс WP_Query. Я видел ответы Майка Шинкеля (расширяющие WP_Query) на подобные вопросы, но я действительно не понимал, как применять его для своих нужд. Было бы здорово, если бы кто-то мог помочь мне с этим.
WP_Query
для получения сообщений, и я не понимаю, как это связано с сообщениями.Ответы:
Если вы выполняете сложные объединения, вы не можете просто использовать фильтр posts_where, потому что вам нужно будет изменить объединение, выбор и, возможно, группирование или упорядочение по разделам запроса.
Лучше всего использовать фильтр «posts_clauses». Это очень полезный фильтр (которым не следует злоупотреблять!), Который позволяет вам добавлять / изменять различные части SQL-кода, автоматически генерируемого множеством строк кода в ядре WordPress. Подпись обратного вызова фильтра:
function posts_clauses_filter_cb( $clauses, $query_object ){ }
и он ожидает вашего возврата$clauses
.Статьи
$clauses
массив, содержащий следующие ключи; каждый ключ является строкой SQL, которая будет напрямую использоваться в окончательном операторе SQL, отправляемом в базу данных:Если вы добавляете таблицу в базу данных (делайте это только в том случае, если вы абсолютно не можете использовать post_meta, user_meta или таксономии), вам, вероятно, придется коснуться более чем одного из этих предложений, например,
fields
(«SELECT») часть заявления SQL), тоjoin
(все ваши таблицы, другие , чем в вашем «FROM» статьи), и возможноorderby
.Изменение пунктов
Лучший способ сделать это - сделать ссылку на соответствующий ключ из
$clauses
массива, который вы получили из фильтра:Теперь, если вы измените
$join
, вы на самом деле будете вносить непосредственные изменения,$clauses['join']
поэтому изменения будут внесены,$clauses
когда вы его вернете.Сохранение оригинальных статей
Скорее всего (нет, серьезно, слушайте), вы захотите сохранить существующий SQL, который WordPress сгенерировал для вас. Если нет, то вам, вероятно, следует
posts_request
вместо этого взглянуть на фильтр - это полный запрос mySQL непосредственно перед отправкой в базу данных, так что вы можете полностью его забить своим собственным. Зачем тебе это делать? Вы, вероятно, нет.Итак, чтобы сохранить существующий SQL в предложениях, не забудьте добавлять к предложениям, а не присваивать им (т. Е.
$join .= ' {NEW SQL STUFF}';
Не использовать$join = '{CLOBBER SQL STUFF}';
. Обратите внимание, что поскольку каждый элемент$clauses
массива является строкой, если вы хотите добавить к нему, вы, вероятно, захотите вставить пробел перед любыми символьными токенами, в противном случае вы, вероятно, создадите некоторую ошибку синтаксиса SQL.Вы можете просто предположить, что в каждом из предложений всегда будет что-то, поэтому не забывайте начинать каждую новую строку с пробела, как в:,
$join .= ' my_table
или вы всегда можете добавить небольшую строку, которая добавляет пробел, только если вам нужно:Это стилистическая вещь больше всего на свете. Важно помнить: всегда оставляйте пробел ДО вашей строки, если вы добавляете к предложению, в котором уже есть некоторый SQL!
Положить его вместе
Первое правило разработки WordPress - стараться использовать как можно больше основных функций. Это лучший способ проверить вашу работу на будущее. Предположим, что основная команда решает, что WordPress теперь будет использовать SQLite, Oracle или другой язык баз данных. Любой рукописный mySQL может стать недействительным и сломать ваш плагин или тему! Лучше позволить WP генерировать как можно больше SQL самостоятельно и просто добавлять нужные биты.
Итак, первым делом
WP_Query
нужно использовать как можно больше ваших базовых запросов. Точный метод, который мы используем для этого, во многом зависит от того, где должен появиться этот список сообщений. Если бы это был подраздел страницы (а не ваш основной запрос), который вы бы использовалиget_posts()
; если это основной запрос, я полагаю, что вы можете использовать егоquery_posts()
и покончить с ним, но правильный способ сделать это - перехватить основной запрос до того, как он попадет в базу данных (и потребляет серверные циклы), поэтому используйтеrequest
фильтр.Итак, вы сгенерировали свой запрос, и SQL будет создан. Ну, на самом деле, оно было создано, просто не отправлено в базу данных. Используя
posts_clauses
фильтр, вы добавите свою таблицу отношений сотрудников в список. Давайте назовем эту таблицу {$ wpdb-> prefix}. 'user_relationship', и это таблица пересечений. (Кстати, я рекомендую вам обобщить эту структуру таблицы и превратить ее в правильную таблицу пересечений со следующими полями: 'отношение_идентификатора', 'идентификатор_пользователя', 'связанный_пользователь_идентификатор', 'тип_отношения'; это гораздо более гибкий и мощный инструмент. .. но я отвлекся)Если я понимаю, что вы хотите сделать, вы хотите передать идентификатор лидера, а затем просматривать только сообщения от подписчиков этого лидера. Я надеюсь, что понял это правильно. Если это неправильно, вам придется взять то, что я говорю, и адаптировать его к вашим потребностям. Я придерживаюсь вашей структуры таблицы: у нас есть
leader_id
иfollower_id
. Таким образом, JOIN будет{$wpdb->posts}.post_author
включен в качестве внешнего ключа для «follower_id» в вашей таблице «user_relationship».источник
Я отвечаю на этот вопрос очень поздно и мои извинения за то же самое. Я был слишком занят сроками, чтобы заниматься этим.
Большое спасибо @ m0r7if3r и @kaiser за предоставление базовых решений, которые я мог бы расширить и внедрить в свое приложение. В этом ответе подробно рассказывается о моей адаптации решений, предлагаемых @ m0r7if3r и @kaiser.
Во-первых, позвольте мне объяснить, почему этот вопрос был задан в первую очередь. Из вопроса и его комментариев можно понять, что я пытаюсь заставить WP_Query получать сообщения всех пользователей (лидеров), за которыми следует данный пользователь (подписчик). Отношения между последователем и лидером хранятся в пользовательской таблице
follow
. Наиболее распространенным решением этой проблемы является извлечение идентификаторов пользователей всех лидеров последователя из таблицы следования и размещение их в массиве. Увидеть ниже:Если у вас есть массив лидеров, вы можете передать его в качестве аргумента WP_Query. Увидеть ниже:
Приведенное выше решение является самым простым способом достижения желаемых результатов. Тем не менее, это не масштабируется. В тот момент, когда у вас есть последователь, следующий за десятками и тысячами лидеров, результирующий массив идентификаторов лидеров станет чрезвычайно большим и заставит ваш сайт WordPress использовать 100–250 МБ памяти при каждой загрузке страницы и в конечном итоге привести к сбою сайта. Решением проблемы является запуск SQL-запроса непосредственно в базе данных и получение соответствующих сообщений. Именно тогда решение @ m0r7if3r пришло на помощь. Следуя рекомендации @ kaiser, я решил протестировать обе реализации. Я импортировал около 47 тысяч пользователей из файла CSV, чтобы зарегистрировать их в новой тестовой установке WordPress. В процессе установки работала тема Twenty Eleven. После этого я запустил цикл for, чтобы около 50 пользователей следили за каждым другим пользователем. Разница во времени запросов для решения @kaiser и @ m0r7if3r была ошеломляющей. Решение @ kaiser обычно занимает от 2 до 5 секунд для каждого запроса. Я предполагаю, что вариация происходит, когда WordPress кэширует запросы для последующего использования. С другой стороны, решение @ m0r7if3r продемонстрировало время запроса в среднем 0,02 мс. Для тестирования обоих решений у меня было индексирование ON для столбца leader_id. Без индексации время запроса значительно увеличилось.
Использование памяти при использовании решения на основе массива составляло около 100–150 МБ и уменьшалось до 20 МБ при запуске прямого SQL.
Я столкнулся с проблемой решения @ m0r7if3r, когда мне нужно было передать идентификатор подписчика в функцию фильтра posts_where. По крайней мере, насколько мне известно, WordPress не позволяет передавать переменные в функции filer. Вы можете использовать глобальные переменные, но я хотел избежать глобальных. В итоге я расширил WP_Query, чтобы наконец решить проблему. Итак, вот окончательное решение, которое я реализовал (на основе решения @ m0r7if3r).
Примечание: в конце концов я попробовал вышеуказанное решение с 1,2 миллионами записей в следующей таблице. Среднее время запроса составляло около 0,060 мс.
источник
Вы можете сделать это с помощью полностью SQL-решения, используя
posts_where
фильтр. Вот пример этого:Я думаю, что может быть способ сделать это
JOIN
, но я не могу придумать это. Я продолжу играть с этим и обновлю ответ, если я получу это.В качестве альтернативы, как предложил @kaiser , вы можете разделить его на две части: получение лидеров и выполнение запроса. Я чувствую, что это может быть менее эффективно, но это, безусловно, более понятный путь. Вы должны проверить эффективность самостоятельно, чтобы определить, какой метод лучше, поскольку вложенные SQL-запросы могут работать довольно медленно.
ИЗ КОММЕНТАРИЙ:
Вы должны поместить функцию в свою
functions.php
и сделать всеadd_filter()
правильно, прежде чем вызываетсяquery()
методWP_Query
. Сразу после этого следует сделатьremove_filter()
так, чтобы это не повлияло на другие запросы.источник
prepare()
. Надеюсь, вы не против редактирования. И да: Производительность имеет быть измерено ОП. Во всяком случае: я все еще думаю, что это должно быть просто usermeta и ничего больше.functions.php
и сделать всеadd_filter()
правильно, прежде чем вызываетсяquery()
методWP_Query
. Сразу после этого следует сделатьremove_filter()
так, чтобы это не повлияло на другие запросы. Я не уверен, в чем будет проблема с перезаписью URL, я использовалposts_where
много раз и никогда не видел этого ...Тег шаблона
Просто поместите обе функции в свой
functions.php
файл. Затем настройте первую функцию и добавьте свое имя таблицы. Затем вам понадобится попытка / ошибка, чтобы избавиться от текущего идентификатора пользователя в результирующем массиве (см. Комментарий).Внутри шаблона
Здесь вы можете делать все, что вы хотите с вашими результатами.
источник
JOIN
это гораздо дороже. Плюс: как я уже говорил, у нас нет данных испытаний, поэтому, пожалуйста, протестируйте оба ответа и ознакомьте нас с вашими результатами.Вот код OPs из комментариев, чтобы добавить первый набор тестовых пользователей. Я должен быть изменен для примера реального мира.
Мой ответ на этот тест::
Я также должен заявить, что вышеприведенное отслеживание времени не может быть реально измерено, так как это также потребовало бы времени для совместного расчета цикла. Лучше было бы перебрать полученный набор идентификаторов во втором цикле.
дальнейший процесс здесь
источник