Вывод новостей сразу в нескольких новостных лентах — различия между версиями

Материал из Umicms
Перейти к:навигация, поиск
 
(не показаны 23 промежуточные версии этого же участника)
Строка 1: Строка 1:
[[category:Написание кастомных макросов]][[Категория: Верстка в XSLT]][[Категория:Верстка в TPL]][[Категория:API]][[Категория:Модуль_Новости]]
+
[[category:Написание кастомных макросов]][[Категория:API]][[Категория:Модуль_Новости]]
 
'''Актуально для версии 2.9.1'''
 
'''Актуально для версии 2.9.1'''
 +
 
== Задача ==
 
== Задача ==
 +
 
Иногда необходимо, чтобы одна и та же новость отображалась в нескольких лентах новостей, стандартными средствами можно создавать виртуальные или просто копии
 
Иногда необходимо, чтобы одна и та же новость отображалась в нескольких лентах новостей, стандартными средствами можно создавать виртуальные или просто копии
 
новости и перетаскивать их через модуль "Структура" по нужным разделам, а если на сайте сложная структура новостных лент, это не совсем удобно.
 
новости и перетаскивать их через модуль "Структура" по нужным разделам, а если на сайте сложная структура новостных лент, это не совсем удобно.
  
 
Поэтому, нам нужно реализовать функционал, который позволит указывать на странице конкретной новости, в каком разделе её выводить.
 
Поэтому, нам нужно реализовать функционал, который позволит указывать на странице конкретной новости, в каком разделе её выводить.
 +
 
== Решение ==
 
== Решение ==
 +
 
Со стороны административной панели, нам понадобиться создать в типе данных 'Новость' поле типа "ссылка на дерево" с идентификатором 'rubric_link', все
 
Со стороны административной панели, нам понадобиться создать в типе данных 'Новость' поле типа "ссылка на дерево" с идентификатором 'rubric_link', все
 
эти действия производятся в модуле "Шаблоны данных", в результате мы получим примерно следующее:
 
эти действия производятся в модуле "Шаблоны данных", в результате мы получим примерно следующее:
[Файл:News_data_type.png]
+
 
 +
[[Файл:News_data_type.png]]
 +
 
 +
Теперь мы можем у каждой новости указать раздел для вывода:
 +
 
 +
[[Файл:Tree.png]]
 +
 
 +
Разделы мы указали, теперь нам понадобиться кастомный макрос, который будет выводить новости из конкретной ленты новостей, плюс новости из всех лент, у которых в поле с
 +
идентификатором 'rubric_link' выбрана эта лента новостей. Код данного макроса и его описание даны ниже.
 +
 
 +
== Описание макроса ==
 +
 
 +
%news customNewsList()% — выводит новости из выбранной ленты и новости из всех лент новостей, у которых в поле типа "ссылка на дерево" с идентификатором 'rubric_link'
 +
указана выбранная лента.
 +
 
 +
'''Параметры: news customNewsList($elementPath,[$template = "default", $per_page = false, $ignore_paging = false])'''
 +
 
 +
'''$elementPath'''
 +
  Принимает id или путь до ленты новостей, новости из которой будут выводиться макроса
 +
'''$template '''
 +
  Принимает имя шаблона, по которому выводится результат макроса. В XSLT-шаблонизаторе игнорируется.
 +
'''$per_page '''
 +
  Принимает число, которое обозначает максимальное количество новостей. Если этот параметр не указывать, будет взято значение, указанное в настройках модуля «Новости».
 +
'''$ignore_paging '''
 +
  Принимаем булево значение («1» или «0»), указывающее макросу игнорировать значение текущей страницы списка вывода (параметр http-запроса p). То есть, если указать «1»,
 +
  макрос будет всегда выводить только первую страницу списка новостей
 +
 
 +
Для применения этого макроса скопируйте содержимое листинга макроса в файл /classes/modules/news/__custom.php, и не забудьте указать имя метода в permissions.custom.php.
  
 
== Листинг макроса ==
 
== Листинг макроса ==
 +
 +
<source lang="php">
 +
public function customNewsList($elementPath, $template = "default", $per_page = false, $ignore_paging = false){
 +
        //если $per_page не задан, то берем его из настроек модуля Новости
 +
if(!$per_page){
 +
(int) $per_page = $this->per_page;
 +
}
 +
        //загружаем шаблон
 +
list($template_block, $template_block_empty, $template_line) = def_module::loadTemplates("news/".$template, "items_block", "items_block_empty", "item_block");
 +
        //берем параметр 'p'
 +
$currPageNum = (int) getRequest('p');
 +
        //если в $elementPath указан путь до ленты, то вытаскиваем её id
 +
$parentId = $this->analyzeRequiredPath($elementPath);
 +
//если такой страницы нет, то кидаем исключение
 +
if($parentId === false){
 +
throw new publicException(getLabel('error-page-does-not-exist', null, $elementPath));
 +
}
 +
        //задаем массив $itemsFromCurrLent, куда попадут новости из выбранной ленты
 +
$itemsFromCurrLent = array();
 +
        //получаем эти новости:
 +
$currLentItems = new selector('pages');
 +
$currLentItems->types('object-type')->name('news', 'item');
 +
$currLentItems->where('hierarchy')->page($parentId);
 +
        //записываем их в массив $itemsFromCurrLent
 +
$itemsFromCurrLent = $currLentItems->result();
 +
unset($currLentItems);
 +
//задаем массив $itemsWithCurrLink, куда попадут новости из всех лент, у которых задана выбранная лента
 +
$itemsWithCurrLink = array();
 +
        //получаем эти новости
 +
$allLentsItems = new selector('pages');
 +
$allLentsItems->types('object-type')->name('news', 'item');
 +
$allLentsItems->where('rubric_link')->equals($parentId);
 +
        //записываем их в массив $itemsWithCurrLink
 +
$itemsWithCurrLink = $allLentsItems->result();
 +
unset($allLentsItems);
 +
//задаем результирующий массив новостей
 +
$resultItems = array();
 +
        //помещаем в него все элементы из массива $itemsFromCurrLent и $itemsWithCurrLink, удаляем дубли.
 +
$resultItems = array_unique(array_merge($itemsFromCurrLent, $itemsWithCurrLink));
 +
        unset($itemsFromCurrLent, $itemsWithCurrLink);
 +
        //задаем числовую переменную $total, содержащую количество элементов массива $resultItems
 +
(int) $total = count($resultItems);
 +
        //если массив не пустой, то
 +
if($total>0){
 +
                //сортируем элементы массива $resultItems по полю publish_time, то есть по дате публикации
 +
usort($resultItems, function($a, $b){
 +
$a_publishTime = $a->getValue('publish_time');
 +
$b_publishTime = $b->getValue('publish_time');
 +
 +
if ($a_publishTime == $b_publishTime) {
 +
return 0;
 +
}
 +
return ($a_publishTime > $b_publishTime) ? -1 : 1;
 +
});
 +
                //задаем массив $limitedItems
 +
$limitedItems = array();
 +
//если $ignore_paging = true, то массив $limitedItems становится результирующим
 +
if($ignore_paging){
 +
$limitedItems = $resultItems;
 +
                //если $ignore_paging = false, то оставляем в результирующем массиве элементы, учитывая параметр 'p' и $per_page
 +
}else{ 
 +
$offset = $currPageNum * $per_page;
 +
$limitedItems = array_slice($resultItems, $offset, $per_page);
 +
}
 +
unset($resultItems);
 +
                //перебираем элементы массива и обрабатываем их шаблоном
 +
$lines = Array();
 +
$block_arr = Array();
 +
 +
foreach ($limitedItems as $item){
 +
$line_arr = array();
 +
 +
$itemId = $item->id;
 +
$line_arr['attribute:id'] = $item->id;
 +
$line_arr['attribute:link'] = $item->link;
 +
$line_arr['xlink:href'] = "upage://" . $itemId;
 +
$line_arr['void:header'] = $lines_arr['name'] = $item->getName();
 +
$line_arr['node:name'] =  $item->getName();
 +
 +
if($publish_time = $item->getValue('publish_time')){
 +
$line_arr['attribute:publish_time'] = $publish_time->getFormattedDate("U");
 +
}
 +
unset($item);
 +
 +
$lines[] = def_module::parseTemplate($template_line, $line_arr, $itemId);
 +
unset($line_arr);
 +
 +
$this->pushEditable("news", "rubric", $itemId);
 +
unset($itemId);
 +
}
 +
 +
if(is_array($parentId)) {
 +
list($parentId) = $parentId;
 +
}
 +
$block_arr['subnodes:items'] = $block_arr['void:lines'] = $lines;
 +
unset($lines);
 +
 +
$block_arr['total'] = $total;
 +
$block_arr['per_page'] = $per_page;
 +
 +
return def_module::parseTemplate($template_block, $block_arr, $parentId);
 +
        //если массив $resultItems пустой, то выводим блок шаблона $template_block_empty
 +
}else{
 +
return $template_block_empty;
 +
}
 +
}
 +
</source>
 +
 
== Применение в xslt ==
 
== Применение в xslt ==
 +
 +
'''Пример вызова'''
 +
<source lang="xml">
 +
udata://news/customNewsList/183/
 +
</source>
 +
'''XML-ответ UData'''
 +
<source lang="xml">
 +
<udata xmlns:xlink="http://www.w3.org/TR/xlink" module="news" method="customNewsList" generation-time="0.054807">
 +
  <items>
 +
      <item id="189" link="/novosti3/novost5/" xlink:href="upage://189" publish_time="1382102520">Новость5</item>
 +
      <item id="187" link="/novosti2/novost4/" xlink:href="upage://187" publish_time="1382001240">Новость4</item>
 +
      <item id="185" link="/novosti2/novost2/" xlink:href="upage://185" publish_time="1381913100">Новость2</item>
 +
      <item id="184" link="/novosti2/novost1/" xlink:href="upage://184" publish_time="1381826640">Новость1</item>
 +
      <item id="186" link="/news1/novost3/" xlink:href="upage://186" publish_time="1381742040">Новость3</item>
 +
  </items>
 +
  <total>5</total>
 +
  <per_page>10</per_page>
 +
</udata>
 +
</source>
 +
'''Элементы и атрибуты'''
 +
 +
'''<items>'''
 +
 +
    Ветвь, содержащая элементы item — новости.
 +
'''<item>'''
 +
 +
    Элемент, описывающий отдельную новость. Значение элемента — название страницы новости.
 +
'''@id'''
 +
 +
    Идентификатор страницы новости.
 +
'''@link'''
 +
 +
    Ссылка на страницу полного текста новости.
 +
'''@xlink:href'''
 +
   
 +
    Ссылка UPage на страницу полного текста новости.
 +
'''@publish_time'''
 +
 +
    Время публикации новости в UNIX TIMESTAMP.
 +
 +
'''<total>'''
 +
 +
  Общее количество полученных новостей.
 +
'''<per_page>'''
 +
 +
  Количество новостей, отображаемых на странице.
 +
 
== Применение в tpl ==
 
== Применение в tpl ==
 +
 +
'''Пример вызова макроса'''
 +
 +
%news customNewsList('183')%
 +
 +
'''Используемые шаблоны'''
 +
 +
Макрос оперирует шаблонами, находящимися в каталоге /tpls/news/. Вывод макроса осуществляется по шаблону, указанному в параметре template.
 +
Вы можете не указывать этот параметр, тогда для вывода будет использован шаблон по умолчанию — default.tpl.
 +
 +
'''Используемые блоки шаблона'''
 +
 +
'''items_block'''
 +
 +
Выводит обрамляющий блок для вывода результатов работы макроса, куда будут подставляться результирующие элементы. Отдельных новости будут отрисованы по блоку item.
 +
 +
%items%
 +
 +
    Выводит список страниц, отрисованных с помощью блока item_block.
 +
 +
'''item_block'''
 +
 +
Отвечает за вывод отдельной новости, полученной в результате работы макроса.
 +
 +
'''%id%'''
 +
 +
    Выводит id новости.
 +
'''%link%'''
 +
 +
    Выводит uri новости.
 +
'''%value%'''
 +
 +
    Выводит название новости.
 +
'''%publish_time%'''
 +
 +
    Выводит время публикации новости в UNIX TIMESTAMP.
 +
'''%total%'''
 +
 +
    Общее количество полученных новостей.
 +
'''%per_page%'''
 +
 +
    Выводит количество новостей, отображаемых на странице.
 +
 +
'''items_block_empty'''
 +
 +
Используется вместо блока items_block в том случае, если новостей, которые необходимо вывести нет.

Текущая версия на 15:44, 31 октября 2013

Актуально для версии 2.9.1

Задача

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

Поэтому, нам нужно реализовать функционал, который позволит указывать на странице конкретной новости, в каком разделе её выводить.

Решение

Со стороны административной панели, нам понадобиться создать в типе данных 'Новость' поле типа "ссылка на дерево" с идентификатором 'rubric_link', все эти действия производятся в модуле "Шаблоны данных", в результате мы получим примерно следующее:

News data type.png

Теперь мы можем у каждой новости указать раздел для вывода:

Tree.png

Разделы мы указали, теперь нам понадобиться кастомный макрос, который будет выводить новости из конкретной ленты новостей, плюс новости из всех лент, у которых в поле с идентификатором 'rubric_link' выбрана эта лента новостей. Код данного макроса и его описание даны ниже.

Описание макроса

%news customNewsList()% — выводит новости из выбранной ленты и новости из всех лент новостей, у которых в поле типа "ссылка на дерево" с идентификатором 'rubric_link' указана выбранная лента.

Параметры: news customNewsList($elementPath,[$template = "default", $per_page = false, $ignore_paging = false])

$elementPath

  Принимает id или путь до ленты новостей, новости из которой будут выводиться макроса

$template

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

$per_page

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

$ignore_paging

  Принимаем булево значение («1» или «0»), указывающее макросу игнорировать значение текущей страницы списка вывода (параметр http-запроса p). То есть, если указать «1», 
  макрос будет всегда выводить только первую страницу списка новостей 

Для применения этого макроса скопируйте содержимое листинга макроса в файл /classes/modules/news/__custom.php, и не забудьте указать имя метода в permissions.custom.php.

Листинг макроса

public function customNewsList($elementPath, $template = "default", $per_page = false, $ignore_paging = false){
        //если $per_page не задан, то берем его из настроек модуля Новости
	if(!$per_page){
		(int) $per_page = $this->per_page;
	}
        //загружаем шаблон
	list($template_block, $template_block_empty, $template_line) = def_module::loadTemplates("news/".$template, "items_block", "items_block_empty", "item_block");
        //берем параметр 'p'
	$currPageNum = (int) getRequest('p');
        //если в $elementPath указан путь до ленты, то вытаскиваем её id
	$parentId = $this->analyzeRequiredPath($elementPath);
	//если такой страницы нет, то кидаем исключение
	if($parentId === false){
		throw new publicException(getLabel('error-page-does-not-exist', null, $elementPath));	
	}
        //задаем массив $itemsFromCurrLent, куда попадут новости из выбранной ленты
	$itemsFromCurrLent = array();
        //получаем эти новости:
	$currLentItems = new selector('pages');
	$currLentItems->types('object-type')->name('news', 'item');
	$currLentItems->where('hierarchy')->page($parentId);
        //записываем их в массив $itemsFromCurrLent
	$itemsFromCurrLent = $currLentItems->result();
	unset($currLentItems);
	//задаем массив $itemsWithCurrLink, куда попадут новости из всех лент, у которых задана выбранная лента
	$itemsWithCurrLink = array();
        //получаем эти новости
	$allLentsItems = new selector('pages');
	$allLentsItems->types('object-type')->name('news', 'item');
	$allLentsItems->where('rubric_link')->equals($parentId);
        //записываем их в массив $itemsWithCurrLink
	$itemsWithCurrLink = $allLentsItems->result();
	unset($allLentsItems);
	//задаем результирующий массив новостей
	$resultItems = array();
        //помещаем в него все элементы из массива $itemsFromCurrLent и $itemsWithCurrLink, удаляем дубли.
	$resultItems = array_unique(array_merge($itemsFromCurrLent, $itemsWithCurrLink));
        unset($itemsFromCurrLent, $itemsWithCurrLink);
        //задаем числовую переменную $total, содержащую количество элементов массива $resultItems
	(int) $total = count($resultItems);
        //если массив не пустой, то
	if($total>0){
                //сортируем элементы массива $resultItems по полю publish_time, то есть по дате публикации
		usort($resultItems, function($a, $b){
			$a_publishTime = $a->getValue('publish_time');
			$b_publishTime = $b->getValue('publish_time');
			
			if ($a_publishTime == $b_publishTime) {
				return 0;
			}
			return ($a_publishTime > $b_publishTime) ? -1 : 1;
		});
                //задаем массив $limitedItems		
		$limitedItems = array();
		//если $ignore_paging = true, то массив $limitedItems становится результирующим
		if($ignore_paging){
			$limitedItems = $resultItems;
                //если $ignore_paging = false, то оставляем в результирующем массиве элементы, учитывая параметр 'p' и $per_page
		}else{  
			$offset = $currPageNum * $per_page;
			$limitedItems = array_slice($resultItems, $offset, $per_page);
		}
		unset($resultItems);
                //перебираем элементы массива и обрабатываем их шаблоном		
		$lines = Array();
		$block_arr = Array();
		
		foreach ($limitedItems as $item){
			$line_arr = array();
			
			$itemId = $item->id;
			$line_arr['attribute:id'] = $item->id;
			$line_arr['attribute:link'] = $item->link;
			$line_arr['xlink:href'] = "upage://" . $itemId;
			$line_arr['void:header'] = $lines_arr['name'] = $item->getName();
			$line_arr['node:name'] =  $item->getName();
			
			if($publish_time = $item->getValue('publish_time')){
				$line_arr['attribute:publish_time'] = $publish_time->getFormattedDate("U");
			}
			unset($item);
			
			$lines[] = def_module::parseTemplate($template_line, $line_arr, $itemId);
			unset($line_arr);
			
			$this->pushEditable("news", "rubric", $itemId);
			unset($itemId);
		}
		
		if(is_array($parentId)) {
			list($parentId) = $parentId;
		}
		$block_arr['subnodes:items'] = $block_arr['void:lines'] = $lines;
		unset($lines);
		
		$block_arr['total'] = $total;
		$block_arr['per_page'] = $per_page;
		
		return def_module::parseTemplate($template_block, $block_arr, $parentId);
        //если массив $resultItems пустой, то выводим блок шаблона $template_block_empty
	}else{
		return $template_block_empty;
	}
}

Применение в xslt

Пример вызова

udata://news/customNewsList/183/

XML-ответ UData

<udata xmlns:xlink="http://www.w3.org/TR/xlink" module="news" method="customNewsList" generation-time="0.054807">
   <items>
      <item id="189" link="/novosti3/novost5/" xlink:href="upage://189" publish_time="1382102520">Новость5</item>
      <item id="187" link="/novosti2/novost4/" xlink:href="upage://187" publish_time="1382001240">Новость4</item>
      <item id="185" link="/novosti2/novost2/" xlink:href="upage://185" publish_time="1381913100">Новость2</item>
      <item id="184" link="/novosti2/novost1/" xlink:href="upage://184" publish_time="1381826640">Новость1</item>
      <item id="186" link="/news1/novost3/" xlink:href="upage://186" publish_time="1381742040">Новость3</item>
   </items>
   <total>5</total>
   <per_page>10</per_page>
</udata>

Элементы и атрибуты

<items>

   Ветвь, содержащая элементы item — новости.

<item>

   Элемент, описывающий отдельную новость. Значение элемента — название страницы новости.

@id

   Идентификатор страницы новости.

@link

   Ссылка на страницу полного текста новости.

@xlink:href

   Ссылка UPage на страницу полного текста новости.

@publish_time

   Время публикации новости в UNIX TIMESTAMP.

<total>

  Общее количество полученных новостей.

<per_page>

  Количество новостей, отображаемых на странице.

Применение в tpl

Пример вызова макроса

%news customNewsList('183')%

Используемые шаблоны

Макрос оперирует шаблонами, находящимися в каталоге /tpls/news/. Вывод макроса осуществляется по шаблону, указанному в параметре template. Вы можете не указывать этот параметр, тогда для вывода будет использован шаблон по умолчанию — default.tpl.

Используемые блоки шаблона

items_block

Выводит обрамляющий блок для вывода результатов работы макроса, куда будут подставляться результирующие элементы. Отдельных новости будут отрисованы по блоку item.

%items%

   Выводит список страниц, отрисованных с помощью блока item_block.

item_block

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

%id%

   Выводит id новости.

%link%

   Выводит uri новости.

%value%

   Выводит название новости.

%publish_time%

   Выводит время публикации новости в UNIX TIMESTAMP.

%total%

   Общее количество полученных новостей.

%per_page%

   Выводит количество новостей, отображаемых на странице.

items_block_empty

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