Вывод заголовков нод, содержащих те же термины, что и текущая, открытая нода.

В альтернативу модулям, создающим блоки на «похожие» или «родственные» материалы, небольшой сниппет, делающий то же самое.

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

Код для отображения «похожих» публикаций, учитывающий все термины ноды во всех ее словарях:

<?php
if ($node = menu_get_object()) {
  $num_nodes = 10; // Устанавливаем ограничение на колличество выводимых сниппетом нод.
  $status    = 1; // 1 - нода опубликована, 0 - не опубликована.
  $terms = taxonomy_node_get_terms($node); // Функция, вызывающая все термины, относящихся к конкретной ноде без учета словаря.
 
  foreach ($terms as $term) {
    $sql = "SELECT DISTINCT n.title, n.nid
                FROM {node} n
                INNER JOIN {term_node} tn
                ON n.nid = tn.nid
                WHERE n.status = %d
                AND tn.tid = %d
                AND n.nid <> %d
                ORDER BY n.created
                DESC"
;
    $result = db_query_range(db_rewrite_sql($sql), $status, $term->tid, $node->nid, 0, $num_nodes);
    $output = node_title_list($result);
  }
  return !empty($output) ? $output : '';
}
?>

Код для отображения «похожих» публикаций, учитывающий термины лишь определенного словаря:

<?php
if ($node = menu_get_object()) {
  $num_nodes = 10; // Устанавливаем ограничение на колличество выводимых сниппетом нод.
  $voc_id = ID_СЛОВАРЯ; // Сюда подставляем ID нужного словаря.
  $status    = 1; // 1 - нода опубликована, 0 - не опубликована.
  $terms = taxonomy_node_get_terms_by_vocabulary($node, $voc_id); //Функция вызывает термины, относящиеся к конкретной ноде и определенному словарю.
 
  foreach ($terms as $term) {
    $sql = "SELECT DISTINCT n.title, n.nid
                FROM {node} n
                INNER JOIN {term_node} tn
                ON n.nid = tn.nid
                WHERE n.status = %d
                AND tn.tid = %d
                AND n.nid <> %d
                ORDER BY n.created
                DESC"
;
    $result = db_query_range(db_rewrite_sql($sql), $status, $term->tid, $node->nid, 0, $num_nodes);
    $output = node_title_list($result);
  }
  return !empty($output) ? $output : '';
}
?>

Варианты сниппета без использования функции menu_get_object().
Ниже приведены версии сниппета, в которых для получения обьекта ноды не используется функция menu_get_object() Drupal API. Приведены больше в информационных целях, нежели как призыв их использовать.

Для отображения «похожих» публикаций, учитывающий все термины ноды во всех ее словарях:

<?php
if (arg(0) == 'node' && is_numeric(arg(1)) && is_null(arg(2))) {
  $num_nodes = 10; // Устанавливаем ограничение на колличество выводимых сниппетом нод.
  $status    = 1; // 1 - нода опубликована, 0 - не опубликована.
  $nid       = (int)arg(1);
  $node      = new stdClass;
  $node->vid = $nid;
  $terms = taxonomy_node_get_terms($node); // Функция, вызывающая все термины, относящихся к конкретной ноде без учета словаря.
 
  foreach ($terms as $term) {
    $sql = "SELECT DISTINCT n.title, n.nid
                FROM {node} n
                INNER JOIN {term_node} tn
                ON n.nid = tn.nid
                WHERE n.status = %d
                AND tn.tid = %d
                AND n.nid <> %d
                ORDER BY n.created
                DESC"
;
    $result = db_query_range(db_rewrite_sql($sql), $status, $term->tid, $nid, 0, $num_nodes);
    $output = node_title_list($result);
  }
  return !empty($output) ? $output : '';
}
?>

Для отображения «похожих» публикаций, учитывающий термины определенного словаря:

<?php
if (arg(0) == 'node' && is_numeric(arg(1)) && is_null(arg(2))) {
  $num_nodes = 10; // Устанавливаем ограничение на колличество выводимых сниппетом нод.
  $voc_id = ID_СЛОВАРЯ; // Сюда подставляем ID нужного словаря.
  $status    = 1; // 1 - нода опубликована, 0 - не опубликована.
  $nid       = (int)arg(1);
  $node      = new stdClass;
  $node->vid = $nid;
  $terms = taxonomy_node_get_terms_by_vocabulary($node, $voc_id); //Функция вызывает термины, относящиеся к конкретной ноде и определенному словарю.
 
  foreach ($terms as $term) {
    $sql = "SELECT DISTINCT n.title, n.nid
                FROM {node} n
                INNER JOIN {term_node} tn
                ON n.nid = tn.nid
                WHERE n.status = %d
                AND tn.tid = %d
                AND n.nid <> %d
                ORDER BY n.created
                DESC"
;
    $result = db_query_range(db_rewrite_sql($sql), $status, $term->tid, $nid, 0, $num_nodes);
    $output = node_title_list($result);
  }
  return !empty($output) ? $output : '';
}
?>

Dalay

Комментарии

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

?- Сможете ли вы за плату доработать "Код для отображения «похожих» публикаций, учитывающий все термины ноды во всех ее словарях"
- к элементам списка добавить четный-нечетный (odd-even). Если возможно, свяжитесь со мной icq 781760

<?php
  if (arg(0) == 'node' && is_numeric(arg(1)) && is_null(arg(2))) {
  $num_nodes = 10;
  $nid = (int)arg(1);
  $node = new stdClass;
  $node->vid = $nid;
  $terms = taxonomy_node_get_terms($node);
  $zebra = ($count  % 2)  ? 'odd' : 'even';
  $count++;
  foreach($terms as $term){
    $sql = "SELECT DISTINCT n.title, n.nid FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE n.status = 1 AND tn.tid = ". $term->tid ." AND n.nid <> ". $nid ." ORDER BY n.created DESC LIMIT $num_nodes";
    $result = db_query(db_rewrite_sql($sql));
  $items = array();
  while ($node = db_fetch_object($result)) {
    $items[] = l($node->title, 'node/'. $node->nid, array('attributes' => array('class' => $zebra)) );
  }
  $output = theme('item_list', $items);
  }
  return $output;
}
?>

Если odd-even нужен неприменно в тегах li списка, то переопределите theme_item_list() как тут показано.

Кстати код у меня почему то подцеплял не все термины, немного изменил так:

 
  if (arg(0) == 'node' && is_numeric(arg(1)) && is_null(arg(2))) {
  $num_nodes = 10;
  $nid = (int)arg(1);
  $node = new stdClass;
  $node->vid = $nid;
 $terms = taxonomy_node_get_terms(node_load($nid));
  $zebra = ($count  % 2)  ? 'odd' : 'even';
  $count++;
  foreach($terms as $term){  $sql = "SELECT DISTINCT n.title, n.nid, n.created FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE n.status = 1 AND tn.tid = ". $term->tid ." AND n.nid != ". $nid ." ORDER BY n.created DESC LIMIT $num_nodes";    $result = db_query(db_rewrite_sql($sql));
  $items = array();
  while ($node = db_fetch_object($result)) {
    $items[] = l($node->title, 'node/'. $node->nid, array('attributes' => array('class' => $zebra)) );
  }
  $output = theme('item_list', $items);
  }
  return $output;
}

Но тут у ссылок добавился класс even при чем у всех ссылок списка, класс odd не присвоился. Хотя и сделал темизацию элементов li через функцию (по Вашей ссылке), все таки что-то там не так :)

node_load() зря вернули: обратный вариант был производительней при тех же результатах работы. Код проверял на LAMP`е предпоследних версий, все отработало на ура.

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

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

Очень пригодился сниппет. Спасибо.
А как вывести не просто заголовки, а тизер с заголовком?
К примеру у меня тизеры создаются модулями Teaser thumbnail и Imagecache'м.

Добавив в sql-запрос соответствующие селекты, как же еще.

Это понятно, но непонятно какие и как )
Подсмотрел запрос в views выводящем заголовки с тизерами, ни о чем не говорит он мне. И вообще запрос из вьюса и близко не похож на тот что в этом сниппете.

<?php
if (arg(0) == 'node' && is_numeric(arg(1)) && is_null(arg(2))) {
  $num_nodes = 10; //Максимальное количество выводимых заголовков нод с похожими терминами.
  $nid = (int)arg(1);
  $node = new stdClass;
  $node->vid = $nid;
  $terms = taxonomy_node_get_terms($node);
  foreach($terms as $term){
$sql = "SELECT
n.title, n.nid, n.created, nr.teaser
FROM
{node} n, {term_node} tn, {node_revisions} nr
WHERE
n.nid = tn.nid  
AND nr.nid = n.nid
AND n.status = 1
AND tn.tid = "
. $term->tid ."
AND n.nid != "
. $nid ."
ORDER BY
n.created
DESC LIMIT
$num_nodes"
;
$result = db_query(db_rewrite_sql($sql));
$items = array();
$num_rows = FALSE;
 while ($anode = db_fetch_object($result)) {
    $items[] = l($anode->title, 'node/'. $anode->nid) .'<p>'. $anode->teaser .'</p>';
    $num_rows = TRUE;
  }
  $output = $num_rows ? theme('item_list', $items) : FALSE;
}
return $output;
}
?>

Я извиняюсь, но опять выводятся только заголовки в виде списка. Проверил настройки display fields, поля не отключены.
Под тизером я подразумевал мелкую фотографию, они у меня создаются модулем teaser thumbnail и imagecache, оба способа по сути дублируют друг друга. Но можно и как вы предложили, вывести просто тизеры (по друпаловской терминологии), и в display fields выбрать необходимые для отображения поля.

Мы явно отошли от курса темы и мне уже не понятно, куда вообще идем. Читайте внимательней ридми и мануалы установленных модулей, более подходящих «волшебных» советов у меня нет.

Спасибо большое, давно искал подобное.
Скажите, а как можно указать в вашем коде конкретный термин, по которому следует отбирать?

Пожалуйста.

Если речь идет именно об этом коде, то плохо представляю зачем и как сие городить. Ежели нужен просто список по определенному/определенным терминам, то гляньте тут.

Все работает, спасибо! Просьба. Имеем общий словарь с общими терминами для двух типов материалов: summary и vacancy. Естественно при открытии любой из этих нод, получим выборку по термину, где будут заголовки обоих типов нод. А как поправить Ваш код, чтобы, например, при открытии vacancy происходила выборка по термину с выводом заголовков только summary, и наоборот?

Можно так:

...
удалено, как неполезное )
...

Результат.
По первому коду:

user warning: Unknown column 'vacancy' in 'where clause' query: SELECT DISTINCT n.title, n.nid, n.created FROM node n INNER JOIN term_node tn ON n.nid = tn.nid WHERE n.type = vacancy AND n.status = 1 AND tn.tid = 93 AND n.nid <> 240 ORDER BY n.created DESC LIMIT 10 in Z:\home\alfa.ru\www\includes\common.inc(1695) : eval()'d code on line 12.

По второму коду:

user warning: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AND n.status = 1 AND tn.tid = 93 AND n.nid <> 240 ORDER BY n.created DESC LIMIT ' at line 1 query: SELECT DISTINCT n.title, n.nid, n.created FROM node n INNER JOIN term_node tn ON n.nid = tn.nid WHERE n.type <> AND n.status = 1 AND tn.tid = 93 AND n.nid <> 240 ORDER BY n.created DESC LIMIT 10 in Z:\home\alfa.ru\www\includes\common.inc(1695) : eval()'d code on line 11.

Типы vacancy и summary существуют?

да, тип материалов vacancy и summary существуют. Тему менять пробовал - не помогло.

) перед return $output; пропишите }

виноват, скобочку, закрывающую условие (if) поставить забыл

Плохо разбираюсь в php. А можно оба кода выложить уже с исправлением (т.е. добавлением скобочки ;)?

Попробуйте этот код:

<?php
if (arg(0) == 'node' && is_numeric(arg(1)) && is_null(arg(2))) {
  $num_nodes = 10;
  $voc_id = ID_нужного_словаря;
  $nid       = (int)arg(1);
  $node      = new stdClass;
  $node->vid = $nid;
  $terms = taxonomy_node_get_terms_by_vocabulary($node, $voc_id);
  $status    = 1;
  foreach ($terms as $term) {
    $sql = "SELECT DISTINCT n.title, n.nid
                FROM {node} n
                INNER JOIN {term_node} tn
                ON n.nid = tn.nid
                WHERE n.status = %d
                AND tn.tid = %d
                AND n.type <> '%s'
                AND n.nid <> %d
                ORDER BY n.created
                DESC"
;
    $result = db_query_range(db_rewrite_sql($sql), $status, $term->tid, $node->type, $nid, 0, $num_nodes);
    $items = array();
    while ($node = db_fetch_object($result)) {
      $items[] = l($node->title, 'node/'. $node->nid, array('attributes' => array('title' => $node->title)));
    }
    $output = theme('item_list', $items);
  }
  return !empty($output) ? $output : '';
}
?>

Все работает! Спасибо за помощь

Если будете этот сниппет на живом сайте пользовать, то про кэширование блока не забывайте, иначе сайт «простудите» такими запросами.

Не могли бы вы подсказать код для вывода заголовков нод, содержащих те же термины, что и текущая, открытая нода, только с условием 100%-го совпадения терминов из двух словарей. Т.е. открыта статья с Термином_1 из Словаря_1 и Термином_1 из Словаря_2, требуется вывести заголовки нод с Термином_1 из Словаря_1 И Термином_1 из Словаря_2

А если vid не равен nid. Т.е. если на сайте используются ревизии этот сниппет не будет работать?
Смутила строка $node->vid = $nid;

Когда постил коды сабжа не ведал про наличие апи-функции menu_get_object(). С ней все получается проще и «прямее».
Используй:

 
  if ($node = menu_get_object()) {
  $num_nodes = 10;
  $terms = taxonomy_node_get_terms($node);
  foreach($terms as $term){

...

  }  
}

Спасибо за оперативный ответ, все отлично работает.

Если использую самый первый код из статьи, то почему то выводятся статьи под другими терминами, а если использую функцию menu_get_object()
то совсем ничего не показывает

  if ($node = menu_get_object()) {
  $num_nodes = 10;
  $terms = taxonomy_node_get_terms($node);
  foreach($terms as $term){
    $sql = "SELECT DISTINCT n.title, n.nid
                FROM {node} n
                INNER JOIN {term_node} tn
                ON n.nid = tn.nid
                WHERE n.status = %d
                AND tn.tid = %d
                AND n.nid <> %d
                ORDER BY n.created
                DESC"
;
    $result = db_query_range(db_rewrite_sql($sql), $status, $term->tid, $node->nid, 0, $num_nodes);
    $output = node_title_list($result);
  }
  return !empty($output) ? $output : '';
}

где ошибка может быть?

Не задано значение переменной $status, подставляющееся в запросе.

итоговый блок выглядит так

if ($node = menu_get_object()) {
  $num_nodes = 10;
$status    = 1;
  $terms = taxonomy_node_get_terms($node);
  foreach($terms as $term){
    $sql = "SELECT DISTINCT n.title, n.nid
                FROM {node} n
                INNER JOIN {term_node} tn
                ON n.nid = tn.nid
                WHERE n.status = %d
                AND tn.tid = %d
                AND n.nid <> %d
                ORDER BY n.created
                DESC"
;
    $result = db_query_range(db_rewrite_sql($sql), $status, $term->tid, $nid, 0, $num_nodes);
    $output = node_title_list($result);
  }
  return !empty($output) ? $output : '';
}

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

Именно так )

Господа в блоке отображается в том числе и та нода на которой Вы находитесь.
$nid поменяйте на $node->nid

Да, действительно. Спасибо за зоркость, исправил.

Не за что :)) Сам Ваш сниппет счас пользую, спасибо!

А как убрать из вывода заголовок текущей ноды?

Он не выводится. Результат работы сниппета можно увидеть на этом сайте.

Здравсвуйте! подскажите пожалуйста, как вывести список заголовков нод, содержащих те же термины, что и текущая, открытая нода, если некоторые термины и словари заменены синонимами?

А вышеприведенные коды их не выводят?

нет, он выводит тока те термины которые не заменены синонимами.

Что под синонимами терминов подразумевается: псевдонимы их адреса или именно их синонимы? Если первое, то должно работать, если второе, то лучше не париться со сниппетами, а использовать один из готовых моделей с d.org.

а можно через Views как-нибудь сделать?

По Views это не сюда.

пытался через друге модули тоже не помогает, похожие материалы отображается только на страницах, которые не заменены синонимами, подскажите может можно как-нибудь снипетом сделать? Нужно примерно как в этом модуле:taxonomy_quick_find

Dalay, Здравсвуйте, помогите пожалуйста разобраться со сниппетом: нужно вывести заголовки нод, содержащих те же термины, что и текущая, открытая нода, сгруппированные по типам "Story" и "Page".Вот почему-то не работает тока:

if (arg(0) == 'node' && is_numeric(arg(1)) && is_null(arg(2))) {
$num_nodes = 10; // Устанавливаем ограничение на колличество выводимых сниппетом нод.
$status    = 1; // 1 - нода опубликована, 0 - не опубликована.
$nid       = (int)arg(1);
$node      = new stdClass;
$node->vid = $nid;
$terms = taxonomy_node_get_terms($node); // Функция, вызывающая все термины, относящихся к конкретной ноде без учета словаря.
$types = array('Pages','Story');

foreach ($terms as $term) {
$sql = "SELECT DISTINCT n.title, n.nid
        FROM {node} n
        INNER JOIN {term_node} tn
        ON n.nid = tn.nid
        WHERE n.status = %d
        AND tn.tid = %d
        AND n.nid <> %d
        ORDER BY n.created DESC"
;
$result = db_query_range(db_rewrite_sql($sql), $status, $term->tid, $nid, 0, $num_nodes);
while ($n = db_fetch_object($result)) {

$output[$types[$n->type]][] = array(array('data' => l($n->title,"node/$n->nid")));
}

foreach ($output as $types[$node->type] => $table) {
     print theme('table', array('data' => $types[$node->type]), $table);
  }
}
  print theme('pager', NULL, $limit);
}

скажите а как вывести не только заголовок, но и изображение товара и цену ?

Да. Как? тоже ломаю голову

Мои соболезнования Вашей голове, уважаемый Вова. Учитывая, что в контексте Друпала под понятиями "изображение товара" и "цена товара" может пониматься большое количество интерпретаций, ответов на такие вопросы не существует.

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

А можно увидеть вариант кода адаптированного под D7?

Ну если только Вам дарована способность видеть то, чего нет.