ApmeM, это делается встроенными средствами. Вы просто создаете в админке новое меню и вставляете его через соответствующий виджет в сайдбар.
Из платных - Woltlab Burning Board и XenForo. Из бесплатных - MyBB и phpBB.
End1, WordPress и дополнения к нему иногда используют выборку категории по slug (https://codex.wordpress.org/Function_Reference/get_category_by_slug). Если будет две категории с одинаковым псевдонимом, то указанная функция будет работать неправильно.
В WordPress slug-и (псевдонимы) для категорий и записей в рамках одного типа должны быть уникальными. Обойти это ограничение сложно. Гораздо проще будет настроить редиект.
Новая команда разработчиков несколько лет назад приняла решение написать вторую версию движка с нуля фреймворке. К сожалению, они сильно недооценили сложность и объем работы. В итоге имеем то что имеем.
Есть еще один интересный проект на Laravel - OctoberCMS. Только через два года после начала разработки этой системой можно было как-то пользоваться. До того же WordPress этой системе еще очень далеко.
Чтобы навести порядок в голове, на начальном этапе лучше изучать как работают готовые системы.
Начать можно с той же Joomla или WordPress. У первой более активно используется объектный подход, а у WP хорошо организована система событий и фильтров. Можно также изучить Yupe, dotplant или Easyii CMS на Yii.
Если у вас на данном этапе возникли проблемы с изучением готовых CMS, то с разработкой таковых на фреймворке будет еще больше проблем.
Ребята из MyBB, например, уже несколько лет разрабатывают вторую версию форума MyBB на Laravel. На данный момент проект еще далек от завершения.
Проверьте подключен ли сам перевод на уровне шаблона (функция load_theme_textdomain).
Сначала вы с таким усердием рассказывали об ORM, Query Builder, фреймворках и т.д., а теперь "а разве не пофиг что в ядре?" :D Основная проблема на самом деле в том, что говнокод там не только в ядре, но и в большинстве стандартных модулей, с которыми так или иначе приходится иметь дело.
В случае с Magento 2, например, код разбит на большое количество модулей, а сама система накладывает достаточно много ограничений на их функционирование и вводит кучу проверок. Как следствие, у программиста нет другого выбора кроме как писать в ее рамках. В итоге система в целом гораздо меньше подвержена ошибкам, проще тестируется и расширяется. Вот, например, метод модели товара, который возвращает связанные товары в Magento:
public function getRelatedProducts(){ if (!$this->hasRelatedProducts()) { $products = []; $collection = $this->getRelatedProductCollection(); foreach ($collection as $product) { $products[] = $product; } $this->setRelatedProducts($products); } return $this->getData('related_products');}
Этот код лучше читается, сделать случайную ошибку в нем гораздо сложнее чем в коде Битрикса выше.
С WordPress ситуация несколько иная. Основное достоинство этой системы - это шикарное API, которое включает огромный набор фильтров, хуков и стандартных функций. Оно позволяет не только изменять поведение системы без вмешательства в код ядра, но и безопасно производить его рефакторинг.
Для того, чтобы "выдрать" из файла стилей нужные куски его требуется полностью загрузить. По умолчанию браузер начинает рендеринг (отображение) страницы после окончания загрузки и обработки всех файлов CSS в секции <head> страницы.
Для ускорения загрузки нужно включить gzip для скриптов и CSS, а также вынести некоторые из них в конец страницы, чтобы они не блокировали отрисовку.
Возьмем, например, файл /bitrix/modules/blog/mysql/blog.php, получение списка записей:
$arSqls["SELECT"] = str_replace("%%_DISTINCT_%%", "", $arSqls["SELECT"]);$r = $obUserFieldsSql->GetFilter();if(strlen($r)>0) $strSqlUFFilter = " (".$r.") ";if (is_array($arGroupBy) && count($arGroupBy)==0){ $strSql = "SELECT ".$arSqls["SELECT"]." ". $obUserFieldsSql->GetSelect()." ". "FROM b_blog B ". " ".$arSqls["FROM"]." ". $obUserFieldsSql->GetJoin("B.ID")." "; if (strlen($arSqls["WHERE"]) > 0) $strSql .= "WHERE ".$arSqls["WHERE"]." "; if(strlen($arSqls["WHERE"]) > 0 && strlen($strSqlUFFilter) > 0) $strSql .= " AND ".$strSqlUFFilter." "; elseif(strlen($arSqls["WHERE"]) <= 0 && strlen($strSqlUFFilter) > 0) $strSql .= " WHERE ".$strSqlUFFilter." "; if (strlen($arSqls["GROUPBY"]) > 0) $strSql .= "GROUP BY ".$arSqls["GROUPBY"]." "; //echo "!1!=".htmlspecialcharsbx($strSql)."<br>"; $dbRes = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__); if ($arRes = $dbRes->Fetch()) return $arRes["CNT"]; else return False;}
Где тут ORM и queryBuilder? :D Это самый обычный говнокод. Такого "счастья" в Bitrix полно даже в самых базовых модулях вроде bitrix/modules/iblock/classes/mysql/iblockelement.php.