Очень интересно наблюдать и за дирижером, его партнер — весь оркестр, а он — и полководец, и воспитатель, и фантазер и наблюдатель..
Для жителей столичных городов всегда
Вы все равно слышите
Он — командир, а дети любят быть командирами..
В последнее время абонементные
Я, например, попыталась.
Конечно, «Репетиция оркестра» Ф...
Феллини — фильм не для детей, но старшие дети уже могут его посмотреть, а узнав в этом великом фильме много-много о жизни, они узнают в нем, как всегда у Феллини, много и о музыке..
Они общаются на языке
Одна из тенденций современного отношения
[series-info:left]
Задача: показывать на страницах материалов блок "См. также". В блок должны входить несколько последних заголовков материалы на похожую тему.
Вопсользуемся таксономией, создадим словарь (например, "Ключевые слова"), принадлежность терминам которого и будет определять "похожесть" тем материалов. Проще говоря, если у двух материалов есть хотя бы один общий термин из нашего словаря, считаем их похожими.
Настройки
Мне хотелось бы иметь возможность указывать словарь из всех имеющихся, на основе которого будем строить блок "См. также", и я полагаю, что было бы удобно иметь возможность выбирать, сколько заголовков выводить в блок "Смотри также".
Для создания страницы настроек используем хук hook_settings. Эта функция должна возвращать набор элементов формы, которые должны быть отображены на странице настроек. В нашем случаем это либо поле для выбора словаря и поле для выбора количества выводимых в блоке заголовков, либо сообщение о том, что нужно включить модуль taxonomy.
Мы можем узнать, какие словари у нас есть, воспользовавшись функцией taxonomy_get_vocabularies. У нее может быть один параметр - тип материалов. Если он указан, функция вернет все словари, которые поддерживают указанный тип, но сейчас нам это не нужно. Без параметров эта функция возвращает просто все словари.
<?php
$vocabs=taxonomy_get_vocabularies();
?>
Возвращает она их в виде массива объектов, примерно вот так:
<?php
Array
(
[4] => stdClass Object
(
[vid] => 4
[name] => Галереи изображений
[description] =>
[help] =>
[relations] => 0
[hierarchy] => 1
[multiple] => 0
[required] => 1
[tags] => 0
[module] => taxonomy
[weight] => 0
[nodes] => Array
(
[0] => image
)
)
[2] => stdClass Object
(
[vid] => 2
[name] => Ключевые слова
[description] =>
[help] =>
[relations] => 0
[hierarchy] => 0
[multiple] => 0
[required] => 0
[tags] => 1
[module] => taxonomy
[weight] => 0
[nodes] => Array
(
[0] => news
[1] => page
[2] => review
)
)
)
?>
Для поля выбора словаря нам понадобиться массив возможных значений в виде пар "идентификатор словаря" - "название словаря". Получим его из массива, который возвращает taxonomy_get_vocabularies:
<?php
foreach($vocabs as $vocab)
{
$options[$vocab->vid]=$vocab->name;
}
?>
Суть этого действия в том, что мы перебираем массив словарей $vocabs и формируем новый массив $options, отвечающий нашим требованиям, т.е. примерно такой:
<?php
Array
(
[4] => Галереи изображений
[2] => Ключевые слова
[7] => Куплю/продам
[5] => Структура новостей
[1] => Структура обзоров
[3] => Темы
)
?>
Теперь мы можем его использовать для формирования поля выбора словаря:
<?php
$form["taxonomy_seealso_vocab"]=array('#type'=>"select", '#title'=>t("Choose vocabulary"), '#options'=>$options, '#default_value'=>variable_get("taxonomy_seealso_vocab", 0));
?>
Переменная, которая хранит идентификатор словаря, называется у нас taxonomy_seealso_vocab (между нами говоря, хранится она будет в таблице variable, но об этом позаботится сам Drupal), для ее установки используется select, заголовком для которого будет текст "Choose vocabulary" (или его перевод), вариантами выбора - элементы массива $options, а установленным значением - текущее значение переменной taxonomy_seealso_vocab или 0, если эта переменная еще не была установлена.
С полем выбора количества выводимых заголовков все еще проще. Единственная особенность - использование функции drupal_map_assoc(), которая превращает обычный массив, получаемый функцией range() в ассоциативный, где ключи равны значениям.
<?php
$form["taxonomy_seealso_num"]=array('#type'=>"select", '#title'=>t("Number of titles in \"See also\" block"), '#options'=>drupal_map_assoc(range(3, 10)), '#default_value'=>variable_get("taxonomy_seealso_num", 3));
?>
Не будем усложнять и предложим пользователю возможность выбирать значение этого параметра из промежутка от 3 до 10.
Итак, целиком реализация hook_settings для нашего модуля выглядит так:
<?php
function taxonomy_seealso_settings()
{
// проверяем, включен ли модуль taxonomy
if(module_exist("taxonomy"))
{
// получаем все имеющиеся словари
$vocabs=taxonomy_get_vocabularies();
print_R($vocabs);
// на основе списков словарей строим массив значений
foreach($vocabs as $vocab)
{
$options[$vocab->vid]=$vocab->name;
}
// элемент формы для выбора словаря
$form["taxonomy_seealso_vocab"]=array('#type'=>"select", '#title'=>t("Choose vocabulary"), '#options'=>$options, '#default_value'=>variable_get("taxonomy_seealso_vocab", 0));
// элемент формы для выбора количества выводимых заголовков
$form["taxonomy_seealso_num"]=array('#type'=>"select", '#title'=>t("Number of titles in \"See also\" block"), '#options'=>range(3, 10), '#default_value'=>variable_get("taxonomy_seealso_num", 3));
}
else
{
// если модуль taxonomy не включен, в форме будет только один элемент - сообщение о том, что нужно включить этот модуль
$form[]=array("#type"=>"item", "#title"=>t("Warning!"), t("Please enable <strong>taxonomy</strong> module!"));
}
return $form;
}
?>
Блок
Работа с блоками реализуется через хук hook_block. Эта функция принимает следующие аргументы: $op - операция, совершаемая над блоком (блоками), $delta - номер блока, над которым совершается операция и $edit - массив параметров, передающийся этой функции в случае сохранения конфигурации блока. Последний параметр, впрочем, нам сейчас не пригодится.
Нам нужно всего лишь, чтобы наш блок показывался в списке на странице администрирования блоков, и, конечно, чтобы блок выполнял свою прямую функцию - показывал заголовки материалов "по теме".
На странице администрирования блоков хук taxonomy_seealso_block вызывается с аргументов $op, равным "list". В ответ он должен вернуть масси, содержащий названия всех своих блоков. У нас блок только один, но это ничего не меняет:
<?php
if ($op == 'list') {
$blocks[0]['info'] = t('See also');
return $blocks;
}
?>
Когда блоки показываются на странице, для каждого блока вызывается хук соответствующего модуля, причем аргумент $op в этом случае равен "view", а аргумент $delta - номеру блока в модуле. Что за номер? Это как раз тот номер, под которым нащ блок возвращается хуком на странице администрирования блоков. В нашем случае это 0.
В ответ функция-хук должна вернуть массив, элемент с индексом subject которого должен содержать заголовок блока, а элемент с индексом "content" - тело блока.
<?php
if ($op == 'view') {
switch($delta) {
case 0:
$block['subject'] = t('See also');
$block['content'] = taxonomy_seealso_nodes();
break;
}
return $block;
?>
Целиком реализация hook_block выглядит так:
<?php
function taxonomy_seealso_block($op = 'list', $delta = 0, $edit = array())
{
// если операция - просмотр списка на странице администрирования блоков, возвращаем название блока
if ($op == 'list') {
$blocks[0]['info'] = t('See also');
return $blocks;
}
// если операция - показ блока на странице
else if ($op == 'view') {
// в зависимоти от номера блока возвращаем заголовок и тело
switch($delta) {
case 0:
$block['subject'] = t('See also');
$block['content'] = taxonomy_seealso_nodes();
break;
}
return $block;
}
}
?>
Для удобства мы не будем формировать тело блока прямо в хуке, а вызовем отдельную функцию taxonomy_seealso_nodes(). Это не хук, а наша собственная функция.
Выборка материалов "Смотри также"
Во-первых, нам нужно быть уверенными, что мы находимся на странице материала, а также узнать его идентификатор. Один из способов сделать это - проанализировать адрес страницы с помощью функции arg(), возвращающей указанный его компонент. Этой функцией пользоваться не рекомендуется по идеологическим причинам (as resulting code is hard to read), но мы воспользуемся.
Так вот, если первый компонент адреса - "node", а второй - число, значит, мы находимся на странице материала, и это число - его идентификатор:
<?php
if(arg(0)=="node" && is_numeric(arg(1)))
{
$nid=arg(1);
...
}
?>
Узнаем все термины из нашего словаря, которым принадлежит наш материал с помощью функции taxonomy_node_get_terms_by_vocabulary, которой в качестве первого параметра передадим идентификатор материала, в качестве второго - идентификатор словаря:
<?php
$terms=taxonomy_node_get_terms_by_vocabulary($nid, variable_get("taxonomy_seealso_vocab", 0));
?>
Мы получим массив объектов - терминов, которым принадлежит материал, типа такого:
<?php
Array
(
[72] => stdClass Object
(
[tid] => 72
[vid] => 2
[name] => Буш
[description] =>
[weight] => 0
)
[70] => stdClass Object
(
[tid] => 70
[vid] => 2
[name] => Путин
[description] =>
[weight] => 0
)
)
?>
Из этого всего нам нужны только идентификаторы терминов, т.е. ключи массива, которые мы и получаем:
<?php
$tids=array_keys($terms);
?>
Осталось только выбрать материалы, которые тоже принадлежат хотя бы одному из этих терминов, но не являются текущим материалом, ограничившись желаемым количеством:
<?php
$result = db_query('SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE n.nid!=%d AND tn.tid IN ('. implode(", ", $tids) .') AND n.status = 1 ORDER BY n.created DESC LIMIT %d', $nid, variable_get("taxonomy_seealso_num", 3));
?>
Дальше осталось просто сформировать список заголовков. Каждый заголовок является ссылкой, для формирования которого воспользуемся фукнцией l(). Снова не будем усложнять, передадим этой функции заголовок материала и его "прямую" ссылку. В ответ получим сформированный тег "", причем если у нода есть алиас, ссылка будет именно с его использованием. Пользуйтесь функцией l(), это хорошая функция!
<?php
$items=array();
while($node=db_fetch_object($result))
{
$items[]=l($node->title, "node/".$node->nid)." [".date("d/m/Y", $node->created)."]";
}
?>
Имеем список заголовков $items, пока что в виде массива. Осталось превратить все это в HTML, воспользовавшись функцией темы theme_item_list.
<?php
if(sizeof($items))
{
$output.=theme("item_list", $items);
}
?>
Функция taxonomy_seealso_nodes() полностью:
<?php
function taxonomy_seealso_nodes()
{
$output="";
// все это имеет смысл делать, только если включен модуль taxonomy и установлен словарь для построения блока
if(module_exist("taxonomy") && variable_get("taxonomy_seealso_vocab", 0))
{
//если мы находимя на странице материала
if(arg(0)=="node" && is_numeric(arg(1)))
{
$nid=arg(1);
//получаем все термины указанного словаря, к которым принадлежит материал
$terms=taxonomy_node_get_terms_by_vocabulary($nid, variable_get("taxonomy_seealso_vocab", 0));
//если если есть хоть один термин, поищем другие материалы, принадлежащие этому термину (терминам)
if(sizeof($terms))
{
$tids=array_keys($terms);
$result = db_query('SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE n.nid!=%d AND tn.tid IN ('. implode(", ", $tids) .') AND n.status = 1 ORDER BY n.created DESC LIMIT %d', $nid, variable_get("taxonomy_seealso_num", 3));
$items=array();
// получаем массив ссылок на похожие материалы
while($node=db_fetch_object($result))
{
$items[]=l($node->title, "node/".$node->nid)." [".date("d/m/Y", $node->created)."]";
}
// если есть хотьодна такая ссылка, формируем тело блока
if(sizeof($items))
{
$output.=theme("item_list", $items);
}
}
}
}
return $output;
}
?>
| Attachment | Size |
|---|---|
| taxonomy_seealso-4.7.0.zip | 1.03 KB |

