Скрыть ноду из списка

Главные вкладки

Аватар пользователя Wolf-alone Wolf-alone 5 августа 2012 в 5:56

Доброго времени суток! Помогите пожалуйста решить следующую задачу:

Дано:
1. Сайт Drupal 7
2. Несколько нод (пример во вложенно файле)

Задача:
1. Скрыть одну (две, три и т.д.) но для текущего пользователя. То есть, временно удалить их из списка вывода.

Я уверен, что есть какая-то апи-функция (Drupal-API), формирующая список но для вывода, непосредственно перед тем, как их выводить, но никак не могу её найти в документации.

Пример:
Заранее известно, что нода с заголовком "Блюдо 2" содержит контент который текущей пользователь видеть не хочет (например, не цензурные выражения), соответственно, в результатах выдачи нам нужно эту ноду скрыть. Подскажите пожалуйста, название API-функции, которую можно/нужно использовать для этих целей.

Благодарю за внимание.

ВложениеРазмер
Иконка изображения hide_node.png55.02 КБ

Комментарии

Аватар пользователя Wolf-alone Wolf-alone 5 августа 2012 в 12:15

Уточнение:
Я имею в виду реализацию, на уровне модуля (программирование).

Уже попробовал:

Получил список всех нод с помощью функции:
hook_node_load()

Попытался сделать:
unset для одной из нод - эффекта это не дало никакого. При этом, например, заголовок любой из нод - я могу сменить без каких либо проблем. А вот временно удалить (скрыть) её из вывода - не получается.

Удалять ноду совсем - не нужно, нужно просто временно убрать её из результатов выдачи, для текущего пользователя. Говоря ещё точнее - нужно сделать что-то на подобии "Unpublic" (не опубликовано) для отдельно взятой ноды, при этом, видеть эту ноду не должен только текущий пользователь.

Жизненный пример:

У нас есть 5 нод, 2 из них содержат не цензурные выражения. По умолчанию, пользователю должны показываться только "цензурные" ноды, то есть, оставшиеся 3. При желании просмотреть все ноды - пользователь жмёт на ссылку-переключатель, которая записывает в куки соответствующее значение и пользователь видит все ноды и цензурные и нет. При повторном нажатии на "переключатель" пользователь видит только те ноды, которые прошли цензуру.

Основываясь, на выше описанном примере - скрыть нам нужно как раз те ноды, которые не прошли цензуру. Список этих нод (их ID) - известен заранее.

P.S. Использую Drupal 7.15.

Аватар пользователя imarat imarat 5 августа 2012 в 17:28

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

Аватар пользователя Wolf-alone Wolf-alone 5 августа 2012 в 17:51

Опишу ситуацию ещё более подробно. У нас есть пользователь, который зашел на сайт. У этого пользователя, есть некая кука в браузере, в которой содержится значение либо 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(010);
if (
$i 5) {
//Выводим все ноды 
} else {
//Выводим все ноды, кроме нод с идентификатором 2 и 3 (проще говоря, удаляем из списка нод подлежащих выводу (рендерингу) ноды с идентификаторы которых == 2 или == 3)
}
?>

Подобный функционал реализуем?

Аватар пользователя Wolf-alone Wolf-alone 5 августа 2012 в 21:26

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

Доп. информация:
При использовании hook_node_load() переменная $node содержит список всех нод, которые будут рендерится (выводится). Если у определённой ноды установить $node->status = 0; она снимается с публикации, но её тизер всё равно виден ЛЮБОМУ пользователю, а при попытке нажать "Подробнее" пользователю выдаётся сообщение, что доступ к этой ноде ему запрещён, что не совсем верно. Ноды не должно быть в списке вообще. Попытки просто удалить элемент из этого массива - так же, не дают желаемого эффекта, так как ноды продолжают выводиться в изначальном порядке, даже если удалить каждый элемент массива.

Уверен, что есть какая-то функция, которая даст доступ к списку нод подлежащих выводу (рендерингу) и/или позволит удалить из этого списка те ноды, которые выводить не нужно.

И, самое главное. В примере выше у нас выводится либо 3 либо 5 нод. Предположим, что на страницу у нас выводится по 2 ноды. Соответственно, в первом случае - страниц с результатом выдачи у нас должно быть две, во втором - три. То есть, например, обернуть данные в слой со свойством CSS "display: block;" - то же, абсолютно не вариант.

Аватар пользователя ser_house ser_house 5 августа 2012 в 22:58

Модули (нормально написанные) используют node_load_multiple. nids для неё они формируют исходя из своих условий. Например, taxonomy.pages.inc:

  if ($nids = taxonomy_select_nodes($term->tid, TRUE, variable_get('default_nodes_main', 10))) {
    $nodes = node_load_multiple($nids);
    $build += node_view_multiple($nodes);

или node_page_default:

function 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. Это, казалось бы, самое очевидное решение: нода есть, аккаунт есть, проверяй и хочешь — запрещай, хочешь — разрешай.
Но есть одна проблема и выглядит она так:

Quote:
Also note that this function isn't called for node listings (e.g., RSS feeds, the default home page at path 'node', a recent content block, etc.)

а это значит, что для умолчальной главной страницы, например, проверка проводиться не будет.

Можно устанавливать дополнительные (детальные) разрешения через hook_node_access_records и потом проверять их в hook_node_grants. К этому способу есть два примечания:
Дополнительные разрешения записываются при сохранении ноды (т.е. к уже существующим так не прицепишься)
И:

Quote:
If you decide to do this, be aware that the node_access_rebuild() function will erase any node ID 0 entry when it is called, so you will need to make sure to restore your {node_access} record after node_access_rebuild() is called.

Про hook_node_load уже написано.
hook_node_view предполагается использовать для добавления чего-нибудь к ноде.

Уф-ф... Вроде всё, что нарыл.

Аватар пользователя Wolf-alone Wolf-alone 5 августа 2012 в 23:14

ser_house, спасибо большое за помощь! Сейчас попробую разобраться со всей этой "бедой" Lol

Ответ получился весьма исчерпывающий, спасибо ещё раз!

Аватар пользователя Wolf-alone Wolf-alone 6 августа 2012 в 1:16

Вроде бы, всё дошло. Что бы "выбрать" нужные ноды, нам необходимо не просто "удалить из списка НЕ нужные", а загрузить список с нужными. Для этих целей используется функция node_load_multiple(), в которую мы передаём идентификаторы нод и пр. информацию. Затем, полученный результат, мы передаём в функцию node_view_multiple().

Я всё верно понял? Для вывода списка "нужных" нод, требуются ещё какие-то манипуляции?

Аватар пользователя ser_house ser_house 6 августа 2012 в 5:51

Не знаю, что ещё может понадобиться. Сделали запрос (с addTag('node_access')), загрузили, вывели. Только как это поможет в данной задаче — тоже не знаю.

Перекрывать все страницы, где выводятся ноды (hook_menu_alter, hook_module_implements_alter и на своей странице делать что хочешь)? Что-то сомнительно...

Аватар пользователя Wolf-alone Wolf-alone 10 августа 2012 в 11:28

ser_house, промучился несколько дней, запутался в конец, но так и не добился достойных результатов.

Если взять во внимание тот факт, что ноды отображаются по тегу таксономии (по ссылки созданной модулем TaxonomyMenu), возможно, есть какая-то возможность, например удалить с нужных нод эти теги, перед их выводом? И тогда ноды не будут отображаться в списке. Существует ли подобная функция, которая бы позволила удалить теги с нод перед построением списка нод через таксономию?

Аватар пользователя ser_house ser_house 10 августа 2012 в 12:19

Удалять что-то или изменять статус на неопубликовано совсем не то.

Что если использовать hook_node_access, а для страниц, где он не вызывается — hook_menu_alter и далее?

Аватар пользователя Wolf-alone Wolf-alone 10 августа 2012 в 12:44

ser_house, hook_menu_alter() - мне кажется, эта функция не понадобиться, по той причине, что меню изменять не нужно. Сами пункты меню строятся на основе другого словаря, грубо говоря словаря "МЕНЮ". Дополнительный словарь нужен как раз для более тонкой фильтрации нод, то есть если мы меню было многоуровневым, то он основе второго словаря - строились бы подпункты. То есть, удалять/добавлять/изменять пункты меню не нужно.

Ещё раз благодарю за информацию! Пойду исследовать hook_node_access().

Аватар пользователя Wolf-alone Wolf-alone 10 августа 2012 в 13:17

Мне в голову, закралась сакральная мысль о том, что hook_node_access() будет работать для зарегистрированного пользователя, скорее всего, даже для группы пользователей. В моём же случае, пользователи чаще всего не будут иметь регистрации (прописки на сайте).

Аватар пользователя ser_house ser_house 10 августа 2012 в 14:31

"Wolf-alone" wrote:
hook_menu_alter() - мне кажется, эта функция не понадобиться, по той причине, что меню изменять не нужно

То есть Вы создаете модуль, но ничего не знаете о hook_menu. Х-м, странно...
"Wolf-alone" wrote:
сакральная мысль

Откуда сакральные мысли? Вроде global $user никто не отменял...

Аватар пользователя ser_house ser_house 10 августа 2012 в 14:31

И ещё. Самоё «правильное», насколько я понимаю, это всё-таки hook_node_access_records и hook_node_grants, но необходимость заниматься сохранением/восстановлением после node_access_rebuild()... Тут вот некоторые даже по крону хотят их перестраивать...

Аватар пользователя Wolf-alone Wolf-alone 10 августа 2012 в 15:53

"ser_house" wrote:
То есть Вы создаете модуль, но ничего не знаете о hook_menu. Х-м, странно...

Я не совсем это имел в виду. Создать ссылку в меню на страницу конфигурации модуля (например) - это наименьшая из проблем, всё это детально описано в книге "Drupal 7 Pro Development".

ser_house, ещё раз спасибо, попробую разобраться с hook_node_access().

UPD. я имел в виду, что для "фильтрации" выводимых нод - эта функция не понадобиться.

Аватар пользователя Wolf-alone Wolf-alone 10 ноября 2015 в 11:48

Пересмотрел ещё раз книги по Drupal на русском и английском языках (название книг - указано выше). Внимательно перечитал документацию, на все функции описанные выше. Мне кажется, это всё не совсем то, что нужно.

Давайте я попробую упростить/уточнить вопрос. У нас есть элементарный друпал-сайт, всё содержимое которого, представляет из себя 3 ноды. Все эти ноды отображаются на главной странице сайта. Пример такого сайта представлен в прилагаемом файле. Существует ли какой-нибудь хук, который позволит модифицировать запрос таким образом, что бы отобразились все ноды, за исключением "Нода-2"?

Аватар пользователя Wolf-alone Wolf-alone 10 августа 2012 в 18:36

"Цитата из документации" wrote:

hook_query_alter() - этот хук используется для изменения запросов, созданных где угодно в Drupal.

Если я правильно понял, получение списка нод на главную страницу, выбор нод по тегу таксономии и просмотр нод - не создают запрос в базу данных?

Аватар пользователя Wolf-alone Wolf-alone 10 августа 2012 в 18:57

"Google" wrote:
hook_query_alter can be used to effectively change or rewrite many of Drupal's system queries, like those generated from views or modules that use the appropriate query building APIs.

Возможно, я как-то не верно интерпретировал выше описанный текст из другого мануала (на английском)? Подскажите пожалуйста, почему хук не вызывается вообще?

Аватар пользователя ser_house ser_house 10 августа 2012 в 19:15

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

Внимательнее прочитайте свою тему (всю).

Аватар пользователя Wolf-alone Wolf-alone 10 августа 2012 в 20:00

"ser_house" wrote:
ответили?

Да! Нашел ответ и в Вашей записи и решение: как его всё-таки заставить вызываться. Не смотря на установленный "Devel", и опцию автоматической очистки (не сохранения) кэша (и в друпале и в браузере) - помогла очистка кэша (в друпале и в браузере). Какая именно помогла - теперь уже сложно сказать. Но, теперь по крайней мере, я знаю наверняка, какую функцию можно попробовать использовать для моих целей. Судя по всему, это будет hook_query_alter(). Осталось только найти примеры модификации запросов. В книге, кажется, таких примеров нет...