Доброго времени суток! Помогите пожалуйста решить следующую задачу:
Дано:
1. Сайт Drupal 7
2. Несколько нод (пример во вложенно файле)
Задача:
1. Скрыть одну (две, три и т.д.) но для текущего пользователя. То есть, временно удалить их из списка вывода.
Я уверен, что есть какая-то апи-функция (Drupal-API), формирующая список но для вывода, непосредственно перед тем, как их выводить, но никак не могу её найти в документации.
Пример:
Заранее известно, что нода с заголовком "Блюдо 2" содержит контент который текущей пользователь видеть не хочет (например, не цензурные выражения), соответственно, в результатах выдачи нам нужно эту ноду скрыть. Подскажите пожалуйста, название API-функции, которую можно/нужно использовать для этих целей.
Благодарю за внимание.
Вложение | Размер |
---|---|
hide_node.png | 55.02 КБ |
Комментарии
Уважаемая администрация, перенесите пожалуйста тему в раздел "Программирование". Благодарю.
Я бы реализовал через Content Access + Rules
Уточнение:
Я имею в виду реализацию, на уровне модуля (программирование).
Уже попробовал:
Получил список всех нод с помощью функции:
hook_node_load()
Попытался сделать:
unset для одной из нод - эффекта это не дало никакого. При этом, например, заголовок любой из нод - я могу сменить без каких либо проблем. А вот временно удалить (скрыть) её из вывода - не получается.
Удалять ноду совсем - не нужно, нужно просто временно убрать её из результатов выдачи, для текущего пользователя. Говоря ещё точнее - нужно сделать что-то на подобии "Unpublic" (не опубликовано) для отдельно взятой ноды, при этом, видеть эту ноду не должен только текущий пользователь.
Жизненный пример:
У нас есть 5 нод, 2 из них содержат не цензурные выражения. По умолчанию, пользователю должны показываться только "цензурные" ноды, то есть, оставшиеся 3. При желании просмотреть все ноды - пользователь жмёт на ссылку-переключатель, которая записывает в куки соответствующее значение и пользователь видит все ноды и цензурные и нет. При повторном нажатии на "переключатель" пользователь видит только те ноды, которые прошли цензуру.
Основываясь, на выше описанном примере - скрыть нам нужно как раз те ноды, которые не прошли цензуру. Список этих нод (их ID) - известен заранее.
P.S. Использую Drupal 7.15.
не понял логику. "нетекущих пользователей" в онлайне нет, любой пользователя открывающий сайт является текущим. Т,е сделать что-то для текущего пользователя в данном случае тоже самое, что сделать для всех пользователей
Опишу ситуацию ещё более подробно. У нас есть пользователь, который зашел на сайт. У этого пользователя, есть некая кука в браузере, в которой содержится значение либо 0, либо 1. Либо этой куки вообще нет, и тогда по мы используем значение по умолчанию = 0;
Если значение куки (или любой отдельно взятой переменной, как Вам удобнее) == 0, то мы должны отображать для этого пользователя только 3 ноды, с номерами 1, 4, 5. Если значение куки (переменной) == 1, то мы должны отображать для пользователя все 5 нод (1, 2, 3, 4, 5).
Приведу ещё 1 пример. Представим себе, что у нас есть простейшая нода (заголовок + текс + термин таксономии). За каждой нодой, закреплён какой-либо термин таксономии (например, "Категория 1" или "Категория 2"). На основе этого словаря у нас построено меню, состоящее из двух пунктов: "Категория 1" и "Категория 2". Когда пользователь кликает по пункту меню "Категория 1" - он видит все ноды за которыми закреплён термин таксономии "Категория 1". Когда пользователь кликает по пункту меню "Категория 2" - он видит все ноды за которыми закреплён термин таксономии "Категория 2". То есть, он видит только те ноды, которые соответствуют определённому условию. При этом, фильтруются ноды на основании одного из терминов таксономии.
Я пытаюсь добиться почти такого же функционала, только не с помощью таксономии, а с помощью программных средств.
Если говорить ещё проще, то выглядеть это будет примерно так:
<?php
$i = rand(0, 10);
if ($i > 5) {
//Выводим все ноды
} else {
//Выводим все ноды, кроме нод с идентификатором 2 и 3 (проще говоря, удаляем из списка нод подлежащих выводу (рендерингу) ноды с идентификаторы которых == 2 или == 3)
}
?>
Подобный функционал реализуем?
В template_preprocess_node сделать проверку юзера, если прошёл — добавить какой-нибудь $variables['access_grant'] = TRUE; а в node.tpl.php весть вывод обернуть в if (isset($access_grant)).
Этак тупо в лоб))
ser_house, большое спасибо за информацию, но это не совсем то, что хотелось бы. Копирование своих файлов в текущий шаблон - не годится.
Доп. информация:
При использовании hook_node_load() переменная $node содержит список всех нод, которые будут рендерится (выводится). Если у определённой ноды установить $node->status = 0; она снимается с публикации, но её тизер всё равно виден ЛЮБОМУ пользователю, а при попытке нажать "Подробнее" пользователю выдаётся сообщение, что доступ к этой ноде ему запрещён, что не совсем верно. Ноды не должно быть в списке вообще. Попытки просто удалить элемент из этого массива - так же, не дают желаемого эффекта, так как ноды продолжают выводиться в изначальном порядке, даже если удалить каждый элемент массива.
Уверен, что есть какая-то функция, которая даст доступ к списку нод подлежащих выводу (рендерингу) и/или позволит удалить из этого списка те ноды, которые выводить не нужно.
И, самое главное. В примере выше у нас выводится либо 3 либо 5 нод. Предположим, что на страницу у нас выводится по 2 ноды. Соответственно, в первом случае - страниц с результатом выдачи у нас должно быть две, во втором - три. То есть, например, обернуть данные в слой со свойством CSS "display: block;" - то же, абсолютно не вариант.
удалено
Модули (нормально написанные) используют node_load_multiple. nids для неё они формируют исходя из своих условий. Например, taxonomy.pages.inc:
$nodes = node_load_multiple($nids);
$build += node_view_multiple($nodes);
или node_page_default:
$select = db_select('node', 'n')
->fields('n', array('nid', 'sticky', 'created'))
->condition('promote', 1)
->condition('status', 1)
->orderBy('sticky', 'DESC')
->orderBy('created', 'DESC')
->extend('PagerDefault')
->limit(variable_get('default_nodes_main', 10))
->addTag('node_access');
$nids = $select->execute()->fetchCol();
if (!empty($nids)) {
$nodes = node_load_multiple($nids);
$build = node_view_multiple($nodes);
Влезть в этот процесс для всех случаев не получится: hook_query_alter и его разновидности hook_query_TAG_alter и node_query_node_access_alter сработают только для помеченных тэгами запросов (в частности, node_query_node_access_alter для db_select с addTag('node_access')). Системные модули наверняка помечают, а вот другие — не обязательно.
Можно попробовать по-другому, через hook_node_access. Это, казалось бы, самое очевидное решение: нода есть, аккаунт есть, проверяй и хочешь — запрещай, хочешь — разрешай.
Но есть одна проблема и выглядит она так:
а это значит, что для умолчальной главной страницы, например, проверка проводиться не будет.
Можно устанавливать дополнительные (детальные) разрешения через hook_node_access_records и потом проверять их в hook_node_grants. К этому способу есть два примечания:
Дополнительные разрешения записываются при сохранении ноды (т.е. к уже существующим так не прицепишься)
И:
Про hook_node_load уже написано.
hook_node_view предполагается использовать для добавления чего-нибудь к ноде.
Уф-ф... Вроде всё, что нарыл.
ser_house, спасибо большое за помощь! Сейчас попробую разобраться со всей этой "бедой"
Ответ получился весьма исчерпывающий, спасибо ещё раз!
Вроде бы, всё дошло. Что бы "выбрать" нужные ноды, нам необходимо не просто "удалить из списка НЕ нужные", а загрузить список с нужными. Для этих целей используется функция node_load_multiple(), в которую мы передаём идентификаторы нод и пр. информацию. Затем, полученный результат, мы передаём в функцию node_view_multiple().
Я всё верно понял? Для вывода списка "нужных" нод, требуются ещё какие-то манипуляции?
Не знаю, что ещё может понадобиться. Сделали запрос (с addTag('node_access')), загрузили, вывели. Только как это поможет в данной задаче — тоже не знаю.
Перекрывать все страницы, где выводятся ноды (hook_menu_alter, hook_module_implements_alter и на своей странице делать что хочешь)? Что-то сомнительно...
ser_house, промучился несколько дней, запутался в конец, но так и не добился достойных результатов.
Если взять во внимание тот факт, что ноды отображаются по тегу таксономии (по ссылки созданной модулем TaxonomyMenu), возможно, есть какая-то возможность, например удалить с нужных нод эти теги, перед их выводом? И тогда ноды не будут отображаться в списке. Существует ли подобная функция, которая бы позволила удалить теги с нод перед построением списка нод через таксономию?
Удалять что-то или изменять статус на неопубликовано совсем не то.
Что если использовать hook_node_access, а для страниц, где он не вызывается — hook_menu_alter и далее?
ser_house, hook_menu_alter() - мне кажется, эта функция не понадобиться, по той причине, что меню изменять не нужно. Сами пункты меню строятся на основе другого словаря, грубо говоря словаря "МЕНЮ". Дополнительный словарь нужен как раз для более тонкой фильтрации нод, то есть если мы меню было многоуровневым, то он основе второго словаря - строились бы подпункты. То есть, удалять/добавлять/изменять пункты меню не нужно.
Ещё раз благодарю за информацию! Пойду исследовать hook_node_access().
Мне в голову, закралась сакральная мысль о том, что hook_node_access() будет работать для зарегистрированного пользователя, скорее всего, даже для группы пользователей. В моём же случае, пользователи чаще всего не будут иметь регистрации (прописки на сайте).
То есть Вы создаете модуль, но ничего не знаете о hook_menu. Х-м, странно...
Откуда сакральные мысли? Вроде global $user никто не отменял...
И ещё. Самоё «правильное», насколько я понимаю, это всё-таки hook_node_access_records и hook_node_grants, но необходимость заниматься сохранением/восстановлением после node_access_rebuild()... Тут вот некоторые даже по крону хотят их перестраивать...
Я не совсем это имел в виду. Создать ссылку в меню на страницу конфигурации модуля (например) - это наименьшая из проблем, всё это детально описано в книге "Drupal 7 Pro Development".
ser_house, ещё раз спасибо, попробую разобраться с hook_node_access().
UPD. я имел в виду, что для "фильтрации" выводимых нод - эта функция не понадобиться.
Пересмотрел ещё раз книги по Drupal на русском и английском языках (название книг - указано выше). Внимательно перечитал документацию, на все функции описанные выше. Мне кажется, это всё не совсем то, что нужно.
Давайте я попробую упростить/уточнить вопрос. У нас есть элементарный друпал-сайт, всё содержимое которого, представляет из себя 3 ноды. Все эти ноды отображаются на главной странице сайта. Пример такого сайта представлен в прилагаемом файле. Существует ли какой-нибудь хук, который позволит модифицировать запрос таким образом, что бы отобразились все ноды, за исключением "Нода-2"?
Если я правильно понял, получение списка нод на главную страницу, выбор нод по тегу таксономии и просмотр нод - не создают запрос в базу данных?
Возможно, я как-то не верно интерпретировал выше описанный текст из другого мануала (на английском)? Подскажите пожалуйста, почему хук не вызывается вообще?
Внимательнее прочитайте свою тему (всю).
Прочёл. Всю. Стоит на что-то обратить особое внимание?
На свой вопрос
ответили?
Да! Нашел ответ и в Вашей записи и решение: как его всё-таки заставить вызываться. Не смотря на установленный "Devel", и опцию автоматической очистки (не сохранения) кэша (и в друпале и в браузере) - помогла очистка кэша (в друпале и в браузере). Какая именно помогла - теперь уже сложно сказать. Но, теперь по крайней мере, я знаю наверняка, какую функцию можно попробовать использовать для моих целей. Судя по всему, это будет hook_query_alter(). Осталось только найти примеры модификации запросов. В книге, кажется, таких примеров нет...