Похожие материалы в Joomla

Код отображения 10 похожих публикаций в материале Joomla!

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

Например, мы знаем, что модули выводятся только в определённых позициях шаблона сайта. Также их можно отобразить в материале. Но для этого нужно опубликовать модуль в материале. А вот возможности отобразить блок информации автоматически в абсолютно всех статьях, или материалах из определённой категории – нет. И чтобы решить подобную задачу придётся либо редактировать каждый материал вручную, что является огромной тратой времени, либо же можно написать код, который будет добавлять нужную информацию в указанные материалы.

Вот об этом и будет наш сегодняшний урок.

Отображение 10 похожих публикаций в Joomla

Перед нами стоит задача написать код, который будет выводить информационный блок под каждым материалом сайта. Назовём этот блок – «Вас может заинтересовать». Это связано с тем, что в нём будут выводиться ссылки на похожие материалы.

Принцип работы этого блока будет следующим:

  1. В блоке будет отображено не более 10 ссылок.
  2. В него будут попадать последние 10 опубликованных материалов именно из той категории, материал которой сейчас просматривает пользователь. Это вполне логично. Ведь если человек читает статью о программировании на Javascript, то вряд ли его заинтересует материал об игре на гитаре, или стихи. Для SEO – это очень хороший способ увеличить показатель удержания. Ведь прочитав одну статью, человек может заинтересоваться каким-то из предложенных вариантом и перейти у другой статье по ссылке.
  3. Тот материал, который в данный момент просматривает пользователь в блок попадать не должен. Это важно для SEO. Нельзя чтобы материал ссылался сам на себя.
  4. Если в категории всего лишь один материал, то вполне логично, что выводить блок похожих новостей не нужно. Ведь пользователь и так смотрит тот единственный материал, который опубликован в этой категории.
  5. Если материал опубликован вне основной категории, то в нём не нужно отображать похожие новости. Это связано с тем, что вне основной категории, мы можем создать родительские категории в которых будут находиться вспомогательные материалы, а не информационные. Например: контакты, карта проезда и т.д. Вполне логично что в таких материалах не нужно выводить блок со статьями.
  6. Ссылка на материал должна формироваться по следующему условию: Если материал находится в категории, которая используется пунктом меню, то в качестве псевдонима нужно использовать именно псевдоним пункта меню. Это тоже очень важно для SEO.

Подготовка файла вывода новостей на сайте

Проверьте есть ли у вас файлы default.php и default_links.php по адресу /сайт/templates/шаблон/html/com_content/article/.

Здесь,

  • сайт – корневая папка вашего сайта;
  • шаблон – шаблон вашего сайта.

Код отображения информационного блока

Описывать что делает данный код особого смысла нет. По комментариям в нём, вы сможете сориентироваться что и для чего написано.

Главное – это правильно вставить этот код в нужный файл.

Откройте файл /сайт/templates/шаблон/html/com_content/article/default и впишите в него следующий код.

<?php
// Вывод блока "Вас может заинтересовать"
// Получаем объект текущей страницы
$app = Joomla\CMS\Factory::getApplication();
$menu = $app->getMenu();
$active = $menu->getActive();

// Получаем ID категории текущей страницы
$category_id = $active->query['id'];

// Получаем пункт меню, который использует данную категорию
$menuItems = $menu->getItems('component', 'com_content');

foreach ($menuItems as $menuItem) {
    if ($menuItem->query['id'] == $category_id) {
        // Проверяем уровень вложенности пункта меню
        if ($menuItem->level >= 3) {
            // Получаем родительский пункт меню
            $parentMenuItem = $menu->getItem($menuItem->parent_id);

            // Проверяем, используется ли родительский пункт меню
            $rootMenuItem = $parentMenuItem->parent_id != 0 ? $menu->getItem($parentMenuItem->tree[0]) : $parentMenuItem;

            // Формируем ссылку
            $menuAlias = $rootMenuItem->alias . '/' . $menuItem->alias;
        } else {
            // Формируем ссылку
            $menuAlias = $menuItem->alias;
        }
        break;
    }
}

// Определяем псевдоним родительской категории, если есть
if ($category->parent_id != 0) {
    $parentCategory = JCategories::getInstance('Content')->get($category->parent_id);
    $parentAlias = $parentCategory->alias;
    $menuAlias = $parentAlias . '/' . $menuAlias;
}

// Формируем итоговую ссылку
$linkMenuAlias = JRoute::_('index.php?option=com_content&view=article&id=' . $article->id . '&catid=' . $category_id . ':' . $category->alias . '&Itemid=' . $menuItem->id);

// Вставляем псевдоним в ссылку
$linkMenuAlias = str_replace($category->alias, $menuAlias, $linkMenuAlias);

// Добавляем псевдоним корневого пункта меню, если нужно
if (isset($rootMenuItem) && $rootMenuItem->level >= 3) {
    $rootAlias = $menu->getItem($rootMenuItem->tree[0])->alias;
    $linkMenuAlias = '/' . $rootAlias . $linkMenuAlias;
}

// Выводим последние 10 публикаций из указанной категории
$db = JFactory::getDbo();
$query = $db->getQuery(true);

$currentDate = JFactory::getDate()->toSql();

$query->select('a.id, a.title, a.alias, a.introtext, c1.alias AS sub_category_alias, c2.alias AS category_alias, c3.alias AS parent_alias');
$query->from($db->quoteName('#__content', 'a'));
$query->leftJoin($db->quoteName('#__categories', 'c1') . ' ON c1.id = a.catid');
$query->leftJoin($db->quoteName('#__categories', 'c2') . ' ON c2.id = c1.parent_id');
$query->leftJoin($db->quoteName('#__categories', 'c3') . ' ON c3.id = c2.parent_id');

if (!empty($category_id)) {
    $query->where('a.catid = ' . (int)$category_id);
} else {
    $query->where('a.catid > 0');
}

$query->where('a.state = 1');
$query->where('c1.published = 1');
$query->where('c1.access IN (' . implode(',', JFactory::getUser()->getAuthorisedViewLevels()) . ')');
$query->where('(a.publish_up = ' . $db->quote('0000-00-00 00:00:00') . ' OR a.publish_up <= ' . $db->quote($currentDate) . ')');

$publishDownClause = '(a.publish_down = ' . $db->quote('0000-00-00 00:00:00') . ' OR a.publish_down >= ' . $db->quote($currentDate) . ')';
$query->where('(' . $publishDownClause . ' OR a.publish_down IS NULL)');

$query->order('a.publish_up DESC');
$query->setLimit('10');

$db->setQuery($query);
$results = $db->loadObjectList();

if (!empty($results)) {
    // проверяем, что количество ссылок больше 1
    if (count($results) > 1) {
        echo '<div class="alert alert-grey" role="alert"><h2 class="float-center">' . JText::_('COM_CONTENT_LAST_PUBLISHED') . '</h2>';
        echo '<ul>';
        foreach ($results as $result) {
		$url = '';
			if (!empty($linkMenuAlias)) {
				$url .= $linkMenuAlias;
			} elseif (!empty($result->parent_alias)) {
				$url .= '/' . $result->parent_alias;
			}
			
			$url .= '/' . $result->alias;
			
			// Пропускаем материал, соответствующий текущей странице
			$currentUrl = JUri::getInstance()->toString();
			$urlWithoutDomain = substr($url, strlen(JUri::root()));
			if (strpos($currentUrl, $urlWithoutDomain) !== false || JUri::getInstance()->getPath() === $urlWithoutDomain) {
				continue;
			}

			//Выводим итоговую ссылку
			echo '<li><a href="' . $url . '">' . $result->title . '</a></li>';
        }
        echo '</ul></div>';
    }
}
?>

Если же в настройках "Маршрутизации" (Материалы → Настройки → Интеграция) выставлена Устаревшая Маршрутизация URL, то нужно заменить этот фрагмент кода.

foreach ($results as $result) {
		$url = '';
			if (!empty($linkMenuAlias)) {
				$url .= $linkMenuAlias;
			} elseif (!empty($result->parent_alias)) {
				$url .= '/' . $result->parent_alias;
			}
			
			$url .= '/' . $result->alias;

на

foreach ($results as $result) {
			$url = '';
			if (!empty($linkMenuAlias)) {
				$url .= '/' . $linkMenuAlias;
			} elseif (!empty($result->parent_alias)) {
				$url .= '/' . $result->parent_alias;
			}
			$url .= '/' . $result->alias;
			if (!empty($result->id)) {
				$url = str_replace('-/', '' . $result->id . '-', $url);
			}
			$url = '/' . trim($url, '/');

Куда вставлять код?

Лично я вставил код в фал default.php в самом низу после:

<?php echo LayoutHelper::render('joomla.content.readmore', ['item' => $this->item, 'params' => $params, 'link' => $link]); ?>
        <?php endif; ?>
    <?php endif; ?>

И перед:

<?php
    if (!empty($this->item->pagination) && $this->item->paginationposition && $this->item->paginationrelative) :
        echo $this->item->pagination;
        ?>
    <?php endif; ?>
    <?php // Content is generated by content plugin event "onContentAfterDisplay" ?>
    <?php echo $this->item->event->afterDisplayContent; ?>

Main Menu