xandeadx.ru Блог музицирующего веб-девелопера

Drupal → Выводим ссылки на похожие материалы без доп. модулей

Опубликовано в

Появилось желание — при просмотре записи в блоге, выводить похожие материалы. Беглый поиск показал наличие 4-х модулей для решения этой задачи (в действительности может и больше). Плюсы и минусы всех четырёх можно посмотреть в сводной табличке на drupal.org — Comparison of Similiar / Relevant by term block modules.

Всё бы хорошо, бери и пользуйся Relevant Content или Similar By Terms, как самыми живыми, но моя дотошность не позволила мне установить модуль в 43 kb (Relevant Content) только ради вывода трёх ссылок =) Решил написать самостоятельно. Получилось довольно просто:

Drupal 6:

function phptemplate_preprocess_node(&$vars) {
  if (!$vars['page'] || !$vars['node'] || !isset($vars['node']->taxonomy) || !count($vars['node']->taxonomy)) {
      return;
  }
 
  $node = $vars['node'];
  $tids = array_keys($node->taxonomy);
  $items = array();
 
  $nodes = db_query_range("
    SELECT n.nid, n.title, COUNT(*) AS hits FROM {node} n
    LEFT JOIN {term_node} tn ON n.nid = tn.nid AND n.vid = tn.vid
    WHERE
      n.type = '%s' AND
      n.status = 1 AND
      tn.tid IN (" . db_placeholders($tids) . ") AND
      n.nid <> %d
    GROUP BY n.nid
    ORDER BY hits DESC, n.created DESC
  ", array_merge(array($node->type), $tids, array($node->nid)), 0, 3);
 
  while ($node = db_fetch_object($nodes)) {
    $items[] = l($node->title, 'node/' . $node->nid);
  }
 
  $vars['content'] .= theme('item_list', $items, 'Похожие материалы');
}

Drupal 7:

function [THEMENAME]_preprocess_node(&$vars) {
  if (!$vars['page'] || !$vars['node'] || !isset($vars['field_tags']) || !count($vars['field_tags'])) {
    return;
  }
 
  $tids = array();
  foreach ($vars['field_tags'] as $tag) {
    $tids[] = $tag['tid'];
  }
 
  $query = db_select('node', 'n');
  $query->fields('n', array('nid', 'title'));
  $query->addExpression('COUNT(*)', 'hits');
  $query->leftJoin('taxonomy_index', 'ti', 'n.nid = ti.nid');
  $query->condition('n.type', $vars['type']);
  $query->condition('n.status', NODE_PUBLISHED);
  $query->condition('ti.tid', $tids, 'IN');
  $query->condition('n.nid', $vars['nid'], '<>');
  $query->groupBy('n.nid');
  $query->orderBy('hits', 'DESC');
  $query->orderBy('n.created', 'DESC');
  $query->range(0, 3);
 
  $vars['content']['similar'] = node_title_list($query->execute(), 'Похожие материалы');
  $vars['content']['similar']['#weight'] = 2;
}

Код добавляет 3 ссылки на похожие материалы при просмотре полной версии ноды. Похожесть определяется с помощью таксономии (поле field_tags в Drupal 7).

Для любителей Views — Выводим ссылки на похожие материалы с помощью Views.

Пример работы ниже ↓

Написанное актуально для Drupal 6, Drupal 7
Похожие записи

Комментарии RSS

Спасибо

недавно тоже долго искал, как сделать related по title, а не через таксономию, сделал на views+views_attach+немного php

Отличная работа.

Около года пользовался Similar by Terms (старая версия), в общем меня устраивал, но иногда раздражал странным поведением. Когда контент, имеющий несколько абсолютно одинаковых тэгов просто не показывался в блоке «похожих материалов» несмотря ни на какие танцы с бубном. Думал о том чтобы обновиться на последнюю версию этого модуля, но из-за того что она переделана на Views (до сих пор не могу полюбить вьюхи) стал смотреть в сторону Relevant content.

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

У меня получилось так: http://www.bestmaps.ru/place/marianskaya-vpadina

Пришлось приджойнить таблицу CCK поля, в связи с чем надо будет замерить производительность

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

в template.php

Я прошу прощения, вставил код в template.php в Drupal 7 и вроде никаких признаков жизни. Может быть, надо ещё что-либо менять в коде, кроме [THEMENAME] ?

сменить имя поля с field_tags на используемое

сменить имя поля с field_tags на используемое

Уважаемый xandeadx, огромное спасибо. Всё так просто, но только после Вашего ответа. Блин, ну почему я сам не мог догадаться? Не, не выйдет из меня друпалера

Работает отлично! (d7). Только одна странная штука.. Выводит вот это:

Notice: Undefined index: field_tags в функции vstheme_preprocess_node()

для нод, типа webform. Так же такие артефакты лезут у любой ноды, которая имеет пустое поле тэгов (или не имеет этого поля вообще).

делайте проверку на наличие поля

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

а как сделать такое же только для ново созданых типов (к примеру блога) ?

if ($vars['node']->type == 'blog') ...

Спасибо, помогло!

Спасибо за сниппет, работает супер, все гениальное просто :)
Если не сложно, поделитесь как завернуть это чудо в fieldset на 7-ке, чтоб получилось как на этом сайте. После трех дней проб и ошибок понял что имеет смысл спросить.

$vars['content']['similar']['#prefix'] = '<fieldset>';
$vars['content']['similar']['#suffix'] = '</fieldset>';

Спасибо, то что надо. Как всегда в дебри полез...

После установки кода на Друпал 7 вместо "Похожие материалы" выводятся крокозябры (шаблон Mayo). С английскими буквами все ОК. Как исправить, чтобы было по русски? Спасибо.

кодировка файла должна быть utf-8

А у меня возникла необходимость вывести текст "Похожие материалы" в теге i , а не h3
Сложно ли это реализовать? Уже замудохался, не получается и всё тут

$vars['content']['similar']['#prefix'] = '<i>Похожие материалы</i>';

Ого, как всё просто оказалось! Ещё раз благодарю!

а можно ли ещё прикрутить вывод определенного cck поля вместе с заголовком?

джоиньте соответствующую таблицу, выбирайте значение

можете в качестве примера расcписать если не сложно, я не силен в php и mysql

$query->leftJoin('tablename', 'alias', 'condition');

Заметил особенность в данном коде. Если всего один материал помечен каким-нибудь одним тегом, то при просмотре этого материала выводится пустой блок с названием "Похожие материалы"
Моих сильно ограниченных знаний PHP хватило на такое решение:

...
    $query->range(0, 10);
 
	$result = node_title_list($query->execute(), null);
	if ($result != null) {
			$vars['content']['similar'] = $result;
			$vars['content']['similar']['#prefix'] = '<i>Похожие материалы:</i>';
			$vars['content']['similar']['#weight'] = 2;
		}

Насчет изящности кода не уверен, но вроде как работает. Мало ли пригодится новичкам типа меня =)

Может кто подскажет каким образом всё это вывести не в контенте, а в левой или правой панелях (по аналогии с меню)? Бьюсь почти неделю.

Поставил код для D7, все работает, огромное спасибо. Но не могу разобраться в расположении кода. В теме Zen как выставить блок в самом конце ноды, перед блоком комментариев. У меня структура получается следующая:

-Текст записи
-Последние материалы
-Метки
-Название рубрики
-Данные автора

а хотелось бы:

-Текст записи
-Метки
-Название рубрики
-Данные автора
-Последние материалы

Заранее благодарен за помощь.

разобрался, в $vars['content']['similar']['#weight'] = 2;
меняем цифру на нужную последовательность

Почему на сайте высвечивается это?
При добавлении статей все хорошо.
А вот сегодня решил страницу добавить - сразу это предупреждение. Как от него избавиться?

Notice: Undefined index: field_tags в функции mobi_drupal7_preprocess_node() (строка 251 в файле public_html/sites/all/themes/mobi_drupal7/template.php).

"делайте проверку на наличие поля" ?

А как ее делать?

if (isset($vars['field_tags'])) ...

У меня, кстати, в template.php уже была функция [THEMENAME]_preprocess_node, я просто добавил в нее приведенный код и...
Notice: Undefined index: tid in zeropoint_preprocess_node() (line 174 of /var/www/u2085107/public_html/kontr-argument.ru/sites/all/themes/zeropoint/template.php).

куда именно вставлять это условие? - if (isset($vars['field_tags'])) ...

у меня ничего не выходит(

function mobi_drupal7_preprocess_node(&$vars) {
    if (!$vars['page'] || !$vars['node'] || !count($vars['field_tags'])) {
        return;
    }
 
    $tids = array();
    foreach ($vars['field_tags'] as $tag) {
        $tids[] = $tag['tid'];
    }
 
    $query = db_select('node', 'n');
    $query->fields('n', array('nid', 'title'));
    $query->addExpression('COUNT(*)', 'hits');
    $query->leftJoin('taxonomy_index', 'ti', 'n.nid = ti.nid');
    $query->condition('n.type', $vars['type']);
    $query->condition('n.status', NODE_PUBLISHED);
    $query->condition('ti.tid', $tids, 'IN');
    $query->condition('n.nid', $vars['nid'], '<>');
    $query->groupBy('n.nid');
    $query->orderBy('hits', 'DESC');
    $query->orderBy('n.created', 'DESC');
    $query->range(0, 10);
 
    $result = node_title_list($query->execute(), null);
    if ($result != null) {
        $vars['content']['similar'] = $result;
        $vars['content']['similar']['#weight'] = 9;
        $vars['content']['similar']['#prefix'] = '<i>Также вам будет интересно:</i><br>';
    }
 
 
    $vars['mynew_region'] = block_get_blocks_by_region('mynew_region');
 
}

вот код который у меня сейчас и который выдает ошибку - Notice: Undefined index: field_tags в функции mobi_drupal7_preprocess_node() (строка 251 в файле /home/u585466205/public_html/sites/all/themes/mobi_drupal7/template.php).

Подскажите, как "Похожие статьи" сделать полем дисплей сьюта? Спасибо заранее!

Notice: Undefined index: tid

решается так

Здравствуйте, подскажите а как в этот снипет для d7 добавить свои классы?

Добрый день!
Вывод с тайтлом еще другие ССK полей возможно через такой вариант?

 $query = db_select('node', 'n');
  $query->fields('n', array('nid', 'title'),'field_name');//или через INNER Join ?
  $query->addExpression('COUNT(*)', 'hits');

Вывод этих полей тайтла и CCK поле провести через foreach?

в 7 нет cck

вывод сск полей по термину в d7 производиться через entity api?
без использование sql запроса?

А как изменить h3 на другой тэг у надписи "Похожие материалы" ???

Речь о D7.

Здравствуйте!
Такая проблема. Нужно вывести в конце статьи, список похожих статей.

Но ничего не получается. Как ни пробую всегда какая-нибудь ошибка вылетает.

1. Оказывается, что [THEMENAME]_preprocess_node, у меня уже использованно и там даже есть какой-то код, вот function corporate_preprocess_node(&$variables) { и т.д.}. В итоге когда я делаю ввожу код с http://xandeadx.ru/blog/drupal/234 function corporate_preprocess_node(&$vars) { то что на сайте} выдается ошибка - Cannot redeclare corporate_preprocess_node() (previously declared in ....) Ну это и есть то, что функция ранее объявлена.

2. Добавлял этот код в уже существующую [THEMENAME]_preprocess_node, выдается вообще какая-то страшенная ошибка, весь материал пропадает.

3. Убираю ранее объявленную функцию, которая была по умолчанию и вставляю ту, что предлагается на сайте, меняя field_tags на свой термин таксономии field_category. В итоге список похожих материалов не выводиться.

Вопрос.

Что я делаю неправильно? И не могли бы вы мне подсказать, как выводить эти похожие материалы?

Заранее благодарен.

Можно ли как-то добавить этот код в блок? например мне нужно между содержимым ноды и похожими новостями вывести ещё какой-то блок, как я могу это сделать?

Здравствуйте, а если полей несколько? То есть у Вас одно поле и соотсветвенно один словарь используется для всех типов контента.
Как переписать код для нескольких полей?

Решил поделиться модулем - http://ssvm.ru/sites/default/files/modules/createoreditfieldtext-7.x-1.0...
И представить на ваш суд. Автора сайта и его читателей.
Нравится мне этот сайт! ....)))) Помогает часто.
И на мысль про этот модуль именно ваш сайт и навёл.
Есть ридми...
Вроде ошибки все подправил... Но если что - не судите строго.
Считаю, что релевантней яндекса, ну или гугла, кто к чему привык... вряд ли правильно выдаст...)))

Здравствуйте! При добавлении кода в template.php на drupal 7 - белый экран :(

т.е. если оставляю [THEMENAME] или же меняю на название темы - получаю белый экран, не подскажите, что может быть причиной?

Включил вывод ошибок:

Fatal error: Cannot redeclare bartik_preprocess_node() (previously declared in /var/www/testsite/themes/bartik/template.php:111) in /var/www/testsite/themes/bartik/template.php on line 183 Call Stack: 0.0027 644320 1. {main}() /var/www/testsite/index.php:0 0.0035 708920 2. drupal_bootstrap() /var/www/testsite/index.php:23 0.0309 1694792 3. _drupal_bootstrap_full() /var/www/testsite/includes/bootstrap.inc:2198 0.1555 17208424 4. drupal_theme_initialize() /var/www/testsite/includes/common.inc:5118 0.1556 17217992 5. _drupal_theme_initialize() /var/www/testsite/includes/theme.inc:100 0.1559 17236648 6. call_user_func() /var/www/testsite/includes/theme.inc:215 0.1559 17236704 7. phptemplate_init() /var/www/testsite/includes/theme.inc:0

вопрос снимается, заработало

Здравствуйте, xandeadx!

Вставила код в конце файла template.php своей темы.
вместо "[THEME]" вставила "mayo" (у меня эта тема). Поля, которые два раза повторяются в Вашем коде "field_tags", оба же раза сменила на название своего поля "field_menu".
Но безрезультатно, в полной ноде не выводится ничего. Абсолютно.
Что может быть не так? Подскажите, пожалуйста?!

кэш

Урррааа!!!
Хоть что-то, да есть.
Только:
1) вместо "Похожие записи" - вопросительные знаки. Полагаю, это кодировка. Читала выше, нужен utf-8
2) выводятся 2 похожие записи.
Спасибо, Вам! Тут столько всего полезного, это не первая инструкция, которой я следую и пытаюсь что-то сделать. Очень познавательно.

Я посмотрела, у меня оказывается кодировка utf-8. А интересно, почему вопросительные знаки, вместо кириллических букв? =(

xandeadx, это опять я.
А как сделать чтобы выводились не просто заголовки, а еще и картинки над ними? Как бы тизеры скажем так, с моим стилем изображения (в нодах использую собственный стиль изоб-ия "preview").
В ноде Article, поле изображения у меня "field_image". Подскажите, плиз как и куда, что добавить в коде?

в конце статьи есть ссылка на способ вывода ссылок с помощью views

$vars['content']['similar']['#weight'] = 1;

если сделать 2 подобных вывода, то первый выводится до body, а второй после. А в ноде, которая выводится print render($content) есть веса?

сори, это веса полей CCK

Спасибо!
А блок "Популярное за месяц" тоже ручками сделан?

да

Может подскажите, каким образом можно вывести подобным образом похожие термины?
Т.е. при просмотре того или иного термина из словаря А (с реферансами на термины из словаря Б), вывести блок с похожими терминами из того же словаря А (которые тоже имеют референсы на теже термины из словаря Б)? Спасибо большое

Views

Здравствуйте.
А можно чуть поподробнее на счет: #comment-3113 и #comment-3114
С типом материала Статья все работает, но с типом Блог не хочет.
Как правильно сделать эту проверку?

Может поделитесь как сделали блок популярное за месяц?

круто а как выводить статьи, сортируя их по тегу, но вывод сделать не списком а например в ротации, типа карусели?

Оставить комментарий

Содержимое этого поля является приватным и не будет отображаться публично. Если у вас есть аккаунт в Gravatar, привязанный к этому e-mail адресу, то он будет использован для отображения аватара.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступные HTML теги: <a> <i> <b> <strong> <code> <ul> <ol> <li> <blockquote> <em> <s>
  • Строки и параграфы переносятся автоматически.
  • Подсветка кода осуществляется с помощью тегов: <code>, <css>, <html>, <ini>, <javascript>, <sql>, <php>. Поддерживаемые стили выделения кода: <foo>, [foo].

Подробнее о форматировании