17 ноября 2009

Размещение одного материала в нескольких категориях

В данной статье рассматривается хак, который позволяет размещать один материал в 3-х категориях, но в приделах одного раздела.

Хак требует изменения как БД так и нескольких файлов самой Joomla, так что перед тем как редактировать файлы, сделайте их бэкапы.

1) Выполним запрос в БД, где # — префикс таблиц в вашей БД:
ALTER TABLE `#_content` ADD `catid2` INT ( 11 ) NOT NULL DEFAULT '-1' AFTER `catid` ;
ALTER TABLE `#_content` ADD `catid3` INT ( 11 ) NOT NULL DEFAULT '-1' AFTER `catid2` ;
ALTER TABLE `#_content` ADD INDEX ( `catid2` );
ALTER TABLE `#_content` ADD INDEX ( `catid3` );


2) Объясним Joomla, что у нас в таблице #_content появились новые поля:
— в файле libraries\joomla\database\table\content.php найдём строку:
var $catid				= null;

и после неё добавим:
var $catid2				= null;
var $catid3				= null;


3) Добавим в админку возможность при создании/редактировании материала указывать несколько категорий:
— в файле administrator\components\com_content\admin.content.html.php найдём строку:
<?php echo $lists['catid']; ?>

и после неё добавим:
<br /><?php echo $lists['catid2']; ?>
<br /><?php echo $lists['catid3']; ?>

— в файле administrator\components\com_content\controller.php найдём строку:
$javascript = "onchange=\"changeDynaList ( 'catid', sectioncategories, document.adminForm.sectionid.options[document.adminForm.sectionid.selectedIndex].value, 0, 0);\"";

и заменим на:
$javascript = "onchange=\"changeDynaList ( 'catid', sectioncategories, document.adminForm.sectionid.options[document.adminForm.sectionid.selectedIndex].value, 0, 0);changeDynaList ( 'catid2', sectioncategories, document.adminForm.sectionid.options[document.adminForm.sectionid.selectedIndex].value, 0, 0);changeDynaList ( 'catid3', sectioncategories, document.adminForm.sectionid.options[document.adminForm.sectionid.selectedIndex].value, 0, 0);\"";

найдём:
foreach ($cat_list as $cat)
{
		if ($cat->section == $section->id) {
				$rows2[] = $cat;
		}
}

и после добавим:
$sectioncategories[$section->id][] = JHTML::_('select.option', '-1', JText::_( 'Select Category' ), 'id', 'title');

найдём:
$lists['catid'] = JHTML::_('select.genericlist',  $categories, 'catid', 'class="inputbox" size="1"', 'id', 'title', intval ($row->catid));

и после добавим:
$lists['catid2'] = JHTML::_('select.genericlist',  $categories, 'catid2', 'class="inputbox" size="1"', 'id', 'title', intval ($row->catid2));
$lists['catid3'] = JHTML::_('select.genericlist',  $categories, 'catid3', 'class="inputbox" size="1"', 'id', 'title', intval ($row->catid3));


4) Научим Joomla показывать материалы, в которых указано несколько категорий:
— в файле components\com_content\models\category.php найдём строку:
$where .= ' AND a.catid = '.(int) $this->_id;

и после неё добавим:
$where .= ' AND (a.catid = '.(int) $this->_id.' OR a.catid2 = '.(int) $this->_id.' OR a.catid3 = '.(int) $this->_id.')';


5) Научим Joomla показывать при просмотре материала все категории, за которыми закреплен данный материал:
— в файле components\com_content\models\article.php найдём строку:
$this->_article = $this->_db->loadObject ();

и после неё добавим:
if ($this->_article->catid2 != -1) {
	$query = 'SELECT title'.
					' FROM #__categories' .
					' WHERE id = '.$this->_article->catid2;
	$this->_db->setQuery ($query);
	$this->_cat2 = $this->_db->loadObject ();
	$this->_article->category2      = $this->_cat2->title;
	}
	
	if ($this->_article->catid3 != -1) {
	$query = 'SELECT title'.
					' FROM #__categories' .
					' WHERE id = '.$this->_article->catid3;
	$this->_db->setQuery ($query);
	$this->_cat3 = $this->_db->loadObject ();
	$this->_article->category3      = $this->_cat3->title;
}

— в файле components\com_content\views\article\tmpl\default.php найдём:
<?php if ($this->params->get ('link_category')) : ?>
	<?php echo '<a href="'.JRoute::_(ContentHelperRoute::getCategoryRoute ($this->article->catslug, $this->article->sectionid)).'">'; ?>
<?php endif; ?>
<?php echo $this->escape ($this->article->category); ?>
<?php if ($this->params->get ('link_category')) : ?>
	<?php echo '</a>'; ?>
<?php endif; ?>

и после добавим:
<?php if ($this->params->get ('link_category') && $this->article->category2) : ?>
	<?php echo ', 
	<a href="'.JRoute::_(ContentHelperRoute::getCategoryRoute ($this->article->catid2, $this->article->sectionid)).'">'; ?>
<?php endif; ?>
<?php echo $this->escape ($this->article->category2); ?>
<?php if ($this->params->get ('link_category') && $this->article->category2) : ?>
	<?php echo '</a>'; ?>
<?php endif; ?>
<?php if ($this->params->get ('link_category') && $this->article->category3) : ?>
	<?php echo ', 
	<a href="'.JRoute::_(ContentHelperRoute::getCategoryRoute ($this->article->catid3, $this->article->sectionid)).'">'; ?>
<?php endif; ?>
<?php echo $this->escape ($this->article->category3); ?>
<?php if ($this->params->get ('link_category') && $this->article->category3) : ?>
	<?php echo '</a>'; ?>
<?php endif; ?>

Примечание: эту же операцию необходимо проделать и с используемыми вами шаблонами, если в них есть этот файл. Например его содержит шаблон ja_purity/html/com_content/article/default.php

6) Познакомим другие модули с нашим хаком (например модули mainmenu и breadcrumbs):
— в файле components\com_content\views\category\view.html.php найдём:
if (($item->params->get ('show_readmore') && @ $item->readmore) || $item->params->get ('link_titles'))
{

и после добавим:
$itemid = JRequest::getInt ('id',0);

найдём:
$item->readmore_link = JRoute::_(ContentHelperRoute::getArticleRoute ($item->slug, $item->catslug, $item->sectionid));

и заменим на:
$item->readmore_link = JRoute::_(ContentHelperRoute::getArticleRoute ($item->slug, $itemid, $item->sectionid));

найдём:
$returnURL = JRoute::_(ContentHelperRoute::getArticleRoute ($item->slug, $item->catslug, $item->sectionid),false);

и заменим на:
$returnURL = JRoute::_(ContentHelperRoute::getArticleRoute ($item->slug, $itemid, $item->sectionid),false);


7) Научим админку показывать при фильтрации по категории материалы привязанные к нескольким категориям:
— в файле administrator\components\com_content\controller.php найдём строку:
$where[] = 'c.catid = ' . (int) $catid;

и заменим на:
$where[] = '(c.catid = ' . (int) $catid .' OR c.catid2 = ' . (int) $catid .' OR c.catid3 = '. (int) $catid .')';


8) Дадим возможность для материалов привязанных к нескольким категориям в столбце «Категория» показывать все категории, к которым привязан материал:
— в файле administrator\components\com_content\controller.php найдём:
// Get the articles
$query = 'SELECT c.*, g.name AS groupname, cc.title AS name, u.name AS editor, f.content_id AS frontpage, s.title AS section_name, v.name AS author' .
		' FROM #__content AS c' .
		' LEFT JOIN #__categories AS cc ON cc.id = c.catid' .
		' LEFT JOIN #__sections AS s ON s.id = c.sectionid' .
		' LEFT JOIN #__groups AS g ON g.id = c.access' .
		' LEFT JOIN #__users AS u ON u.id = c.checked_out' .
		' LEFT JOIN #__users AS v ON v.id = c.created_by' .
		' LEFT JOIN #__content_frontpage AS f ON f.content_id = c.id' .
		$where .
		$order;

и заменим на:
// Get the articles
$query = 'SELECT c.*, g.name AS groupname, cc.title AS name, cc2.title AS name2, cc3.title AS name3, u.name AS editor, f.content_id AS frontpage, s.title AS section_name, v.name AS author' .
		' FROM #__content AS c' .
		' LEFT JOIN #__categories AS cc ON cc.id = c.catid' .
		' LEFT JOIN #__categories AS cc2 ON cc2.id = c.catid2' .
		' LEFT JOIN #__categories AS cc3 ON cc3.id = c.catid3' .
		' LEFT JOIN #__sections AS s ON s.id = c.sectionid' .
		' LEFT JOIN #__groups AS g ON g.id = c.access' .
		' LEFT JOIN #__users AS u ON u.id = c.checked_out' .
		' LEFT JOIN #__users AS v ON v.id = c.created_by' .
		' LEFT JOIN #__content_frontpage AS f ON f.content_id = c.id' .
		$where .
		$order;

— в файле administrator\components\com_content\admin.content.html.php найдём (найдется две строки, сделать для обоих):
$row->cat_link 	= JRoute::_( 'index.php?option=com_categories&task=edit&cid[]='. $row->catid );

и после добавим:
$row->cat_link2 	= JRoute::_( 'index.php?option=com_categories&task=edit&cid[]='. $row->catid2 );
$row->cat_link3 	= JRoute::_( 'index.php?option=com_categories&task=edit&cid[]='. $row->catid3 );

найдём (найдется две строки, сделать для обоих):
<a href="<?php echo $row->cat_link; ?>" title="<?php echo JText::_( 'Edit Category' ); ?>">
	<?php echo $row->name; ?></a>

и после добавим:
<?php if ($row->catid2 && $row->catid2!=-1) : ?>
	<hr /><a href="<?php echo $row->cat_link2; ?>" title="<?php echo JText::_( 'Edit Category' ); ?>">
	<?php echo $row->name2; ?></a>
<?php endif; ?>
<?php if ($row->catid3 && $row->catid3!=-1) : ?>
	<hr /><a href="<?php echo $row->cat_link3; ?>" title="<?php echo JText::_( 'Edit Category' ); ?>">
	<?php echo $row->name3; ?></a>
<?php endif; ?>


9) Добавим возможность указания нескольких категорий в в fronted-редакторе:
— в файле components\com_content\views\article\view.html.php найдём строку:
$lists['catid'] = JHTML::_('select.genericlist',  $categories, 'catid', 'class="inputbox" size="1"', 'id', 'title', intval($article->catid));

и после неё добавим:
$lists['catid2'] = JHTML::_('select.genericlist',  $categories, 'catid2', 'class="inputbox" size="1"', 'id', 'title', intval($article->catid2));
$lists['catid3'] = JHTML::_('select.genericlist',  $categories, 'catid3', 'class="inputbox" size="1"', 'id', 'title', intval($article->catid3));

найдём:
$javascript = "onchange=\"changeDynaList( 'catid', sectioncategories, document.adminForm.sectionid.options[document.adminForm.sectionid.selectedIndex].value, 0, 0);\"";

и заменим на:
$javascript = "onchange=\"changeDynaList ( 'catid', sectioncategories, document.adminForm.sectionid.options[document.adminForm.sectionid.selectedIndex].value, 0, 0);changeDynaList ( 'catid2', sectioncategories, document.adminForm.sectionid.options[document.adminForm.sectionid.selectedIndex].value, 0, 0);changeDynaList ( 'catid3', sectioncategories, document.adminForm.sectionid.options[document.adminForm.sectionid.selectedIndex].value, 0, 0);\"";

найдём:
foreach ($cat_list as $cat)
{
	if ($cat->section == $section->id) {
		$rows2[] = $cat;
	}
}

и после добавим:
$sectioncategories[$section->id][] = JHTML::_('select.option', '-1', JText::_( 'Select Category' ), 'id', 'title');


— в файле components\com_content\views\article\tmpl\form.php найдём строку:
<?php echo $this->lists['catid']; ?>

и после неё добавим:
<br /><?php echo $this->lists['catid2']; ?>
<br /><?php echo $this->lists['catid3']; ?>


По материалам JoomlaForum.RU
+2

Комментарии:12

avatar
  • alex
  • 19 ноября 2009, 12:25
  • 0
Здоровенный хак!
avatar
Спасибо!!! Все работает! Жалко что срок голосования истек :(
avatar
Небольшая ошибочка (лично у меня)

В пункте:
4) Научим Joomla показывать материалы, в которых указано несколько категорий:
— в файле components\com_content\models\category.php найдём строку:
$where .= ' AND a.catid = '.(int) $this->_id;

нужно ЗАМЕНИТЬ, а не после нее добавить, на строку
$where .= ' AND (a.catid = '.(int) $this->_id.' OR a.catid2 = '.(int) $this->_id.' OR a.catid3 = '.(int) $this->_id.')';


Просто если добавить после, то материал не будет отображаться во 2 и 3 категориях.

И еще вопрос админу :) если нужно чтобы материал был в разных категориях алгоритм такой же?
avatar
опечатка, не в катгориях а разделах :)
avatar
опечатка, не в категориях а разделах :)
avatar
я дико извиняюсь, но у меня проблема с модулем «Хлебные крошки».
материал находится в 3 разделах…
если открыть страницу с материалам, то путь по сайту будет отображать ту актегорию, которая выбрана первой при создании статьи, а не ту с которой мы на этот материал попали.

помогите пожалуйста, очень нужно, а то как-то не красиво получается и не правильно :((
avatar
  • jiammer
  • 04 февраля 2011, 11:14
  • 0
огромное спасибо автору! все работает, только как писал(а) koka-land, нужно ЗАМЕНИТЬ
PS: чтоб поблагодарить, даже зарегистрировался ;)
avatar
  • Dgikar
  • 01 сентября 2011, 16:36
  • 0
Скажите, а что-то подобное для Joomla 1.7 можно сделать?
avatar
pedrosoft, вы когда размещаете чужие материалы, не забывайте размещать ссылку на оригинал
avatar
Пардон, не сразу увидел ссылку, тогда лучше обновите материал ибо устаревшая версия.
avatar
Уже давно не занимаюсь joomla, поэтому нет желания обновлять :)
avatar
Добрый день. Не могу в файле content.php найти приведенную строку. Joomla 2.5.22. Помогите решить вопрос.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.