↩️ Назад

Категории

Sitemap XML для Joomla с ЧПУ - Документация

09.07.2026 | коды из категории: Joomla

🗺️ Sitemap XML для Joomla

Генерация карты сайта с правильными ЧПУ на основе структуры меню и категорий
Версия: финальная | PHP 7.0+ | Joomla CMS

📋 Общее описание

Скрипт генерирует XML-карту сайта для Joomla с правильными ЧПУ-адресами на основе структуры меню и категорий. Автоматически определяет приоритеты и частоту обновления для каждой страницы.

🏠 Главная страница

Приоритет 1.0
Частота: daily

📄 Статьи

Динамический приоритет 0.5-0.9
Частота: daily / weekly / monthly

📁 Категории

Приоритет 0.6
Частота: weekly

🔍 Основной функционал

1. Главная страница

2. Статьи

Возраст статьи Приоритет Частота обновления
Младше 7 дней 0.9 daily
Младше 30 дней 0.7 weekly
Старше 30 дней 0.5 monthly

3. Категории

🗺️ Формирование URL

Приоритеты построения ЧПУ:

  1. Путь из меню (самый приоритетный)
    ✅ Пример: /o-neirologii/kak-lechit-golovu
  2. Путь из категории (второй приоритет)
    ✅ Пример: /golovnye-boli/lechenie-golovnoj-boli
  3. Запасной вариант (если нет ЧПУ)
    ⚠️ Пример: /component/content/article/ID-alias
// Пример построения URL
function buildArticleUrl($article, $menuArticleMap, $db) {
    // Приоритет 1: путь из меню
    if (isset($menuArticleMap[$article->id])) {
        return 'https://www.doctorneiro.ru/' . $menuArticleMap[$article->id];
    }
    
    // Приоритет 2: путь из категории
    $categoryPath = getCategoryPath($article->catid, $db);
    if (!empty($categoryPath)) {
        return 'https://www.doctorneiro.ru/' . $categoryPath . '/' . $article->alias;
    }
    
    // Приоритет 3: запасной вариант
    return 'https://www.doctorneiro.ru/component/content/article/' . $article->id;
}

📊 Структура данных

Основные таблицы Joomla:

📋 #__menu

Пункты меню для получения ЧПУ
id alias link path

📄 #__content

Статьи
id alias catid state access

📁 #__categories

Категории
id alias parent_id published

🎯 Особенности реализации

🧠 Умный выбор пути

Если статья имеет несколько пунктов в меню — выбирается самый короткий путь

🌳 Рекурсивное построение

Полная иерархия категорий от корня до текущей

🔒 Фильтрация

Проверка дат публикации, доступа и состояния

⚙️ Технические детали

Зависимости

HTTP заголовки

header('Content-Type: application/xml; charset=utf-8');

Обработка ошибок

📝 Пример вывода

<url>
    <loc>https://www.doctorneiro.ru/o-neirologii/kak-lechit-golovu</loc>
    <lastmod>2026-01-15</lastmod>
    <changefreq>weekly</changefreq>
    <priority>0.7</priority>
</url>

🚀 Рекомендации по использованию

💾 Кеширование

Рекомендуется кэшировать результат на 1-24 часа для снижения нагрузки

🔄 Обновление

Запускать при добавлении или изменении статей

🤖 SEO

Обязательно указать в robots.txt:
Sitemap: https://www.doctorneiro.ru/sitemap.xml

🔧 Возможные улучшения

<?php
/**
 * Sitemap XML - с правильными ЧПУ на основе структуры меню и категорий
 * Версия: финальная
 */

error_reporting(0);
ini_set('display_errors', 0);

define('_JEXEC', 1);
define('JPATH_BASE', __DIR__);

require_once JPATH_BASE . '/includes/defines.php';
require_once JPATH_BASE . '/includes/framework.php';

use Joomla\CMS\Factory;

header('Content-Type: application/xml; charset=utf-8');
echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    <url>
        <loc>https://www.doctorneiro.ru/</loc>
        <lastmod><?php echo date('Y-m-d'); ?></lastmod>
        <changefreq>daily</changefreq>
        <priority>1.0</priority>
    </url>
<?php

try {
    $db = Factory::getDbo();

    // ============================================
    // 1. ПОЛУЧАЕМ ВСЕ ПУНКТЫ МЕНЮ (для определения правильных ЧПУ)
    // ============================================
    $query = $db->getQuery(true);
    $query->select('id, alias, link, path')
          ->from('#__menu')
          ->where('published = 1')
          ->where('client_id = 0');
    $db->setQuery($query);
    $menuItems = $db->loadObjectList();

    // Строим карту: ID статьи => путь из меню
    $menuArticleMap = [];
    foreach ($menuItems as $item) {
        if (strpos($item->link, 'view=article&id=') !== false) {
            preg_match('/id=(\d+)/', $item->link, $matches);
            if (isset($matches[1])) {
                $articleId = (int)$matches[1];
                $menuPath = trim($item->path, '/');
                if (!empty($menuPath)) {
                    // Если для одной статьи несколько пунктов меню — берём самый короткий (обычно главный)
                    if (!isset($menuArticleMap[$articleId]) || strlen($menuPath) < strlen($menuArticleMap[$articleId])) {
                        $menuArticleMap[$articleId] = $menuPath;
                    }
                }
            }
        }
    }

    // ============================================
    // 2. ФУНКЦИЯ ДЛЯ ПОЛУЧЕНИЯ ПУТИ КАТЕГОРИИ (с родителями)
    // ============================================
    function getCategoryPath($catId, $db) {
        $path = [];
        $currentId = (int)$catId;
        
        while ($currentId > 0) {
            $query = $db->getQuery(true);
            $query->select('id, alias, parent_id')
                  ->from('#__categories')
                  ->where('id = ' . $currentId);
            $db->setQuery($query);
            $category = $db->loadObject();
            
            if (!$category || empty($category->alias)) {
                break;
            }
            
            array_unshift($path, $category->alias);
            
            if ($category->parent_id <= 1) {
                break;
            }
            
            $currentId = $category->parent_id;
        }
        
        return implode('/', $path);
    }

    // ============================================
    // 3. ФУНКЦИЯ ДЛЯ ПОСТРОЕНИЯ URL СТАТЬИ
    // ============================================
    function buildArticleUrl($article, $menuArticleMap, $db) {
        // Приоритет 1: если есть путь из меню — используем его
        if (isset($menuArticleMap[$article->id])) {
            return 'https://www.doctorneiro.ru/' . $menuArticleMap[$article->id];
        }
        
        // Приоритет 2: строим из категории
        $categoryPath = getCategoryPath($article->catid, $db);
        if (!empty($categoryPath) && !empty($article->alias) && $article->alias != 'index.php') {
            return 'https://www.doctorneiro.ru/' . $categoryPath . '/' . $article->alias;
        }
        
        // Приоритет 3: запасной вариант
        return 'https://www.doctorneiro.ru/component/content/article/' . $article->id . '-' . ($article->alias ?: 'article');
    }

    // ============================================
    // 4. ВСЕ АКТИВНЫЕ СТАТЬИ
    // ============================================
    $query = $db->getQuery(true);
    $query->select('a.id, a.alias, a.catid, a.created, a.modified, a.publish_up, a.publish_down, a.state, a.access, c.alias AS category_alias, c.published AS category_published')
          ->from('#__content AS a')
          ->leftJoin('#__categories AS c ON a.catid = c.id')
          ->where('a.state = 1')
          ->where('a.access = 1')
          ->where('c.published = 1')
          ->where('c.access = 1')
          ->order('a.id DESC');
    $db->setQuery($query);
    $articles = $db->loadObjectList();

    if ($articles) {
        foreach ($articles as $article) {
            $now = date('Y-m-d H:i:s');
            if ($article->publish_up && $article->publish_up > $now) continue;
            if ($article->publish_down && $article->publish_down < $now) continue;
            if (empty($article->catid) || empty($article->category_alias)) continue;
            
            $date = $article->modified ?: ($article->publish_up ?: $article->created);
            $lastmod = date('Y-m-d', strtotime($date));
            
            $days = (time() - strtotime($date)) / 86400;
            $priority = $days < 7 ? '0.9' : ($days < 30 ? '0.7' : '0.5');
            $freq = $days < 7 ? 'daily' : ($days < 30 ? 'weekly' : 'monthly');
            
            $fullUrl = buildArticleUrl($article, $menuArticleMap, $db);
            // Убираем дублирующие слеши на всякий случай
            $fullUrl = str_replace('//', '/', $fullUrl);
            ?>
            <url>
                <loc><?php echo $fullUrl; ?></loc>
                <lastmod><?php echo $lastmod; ?></lastmod>
                <changefreq><?php echo $freq; ?></changefreq>
                <priority><?php echo $priority; ?></priority>
            </url>
            <?php
        }
    }

    // ============================================
    // 5. ВСЕ КАТЕГОРИИ (только с активными статьями)
    // ============================================
    // Получаем ID категорий, в которых есть активные статьи
    $validCategoryIds = array_unique(array_column($articles, 'catid'));
    
    if (!empty($validCategoryIds)) {
        $query = $db->getQuery(true);
        $query->select('DISTINCT c.id, c.alias, c.parent_id')
              ->from('#__categories AS c')
              ->where('c.id IN (' . implode(',', $validCategoryIds) . ')')
              ->where('c.published = 1')
              ->where('c.access = 1');
        $db->setQuery($query);
        $categories = $db->loadObjectList();
        
        if ($categories) {
            foreach ($categories as $cat) {
                $categoryPath = getCategoryPath($cat->id, $db);
                $fullUrl = 'https://www.doctorneiro.ru/' . ($categoryPath ?: 'category-' . $cat->id);
                ?>
                <url>
                    <loc><?php echo $fullUrl; ?></loc>
                    <changefreq>weekly</changefreq>
                    <priority>0.6</priority>
                </url>
                <?php
            }
        }
    }

} catch (Exception $e) {
    // Игнорируем ошибки
}
?>
</urlset>
Оцените статью
Всего: 0



Категории:

Категории

Комментарии

Пока нет комментариев. Будьте первым!

Оставить комментарий

← Назад к списку

Посетителей сегодня: 0
о блоге | карта блога | 📡 Подписаться на RSS

© Digital Specialist | Не являемся сотрудниками Google, Яндекса и NASA