This Joomla 4 override allows you to display a knwoledge base and its search bar simply using Joomla's com_content
component and mod_finder
module. At the bottom of this article, you can download the files of the override.
This override require Material Design Bootstrap as frontend framework.
Joomla 4 frontend rendering
The search bar
PhP markup mod_finder/override-kb.php
<?php
/**
* @package Joomla.Site
* @subpackage mod_finder
* @author web-eau.net
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
use Joomla\Module\Finder\Site\Helper\FinderHelper;
// Load the smart search component language file.
$lang = $app->getLanguage();
$lang->load('com_finder', JPATH_SITE);
$input = '<input type="text" name="q" id="mod-finder-searchword' . $module->id . '" class="p-3 shadow-4 js-finder-search-query form-control" value="' . htmlspecialchars($app->input->get('q', '', 'string'), ENT_COMPAT, 'UTF-8') . '"'
. ' placeholder="Search in the Joomla knowledge base..." size="150" aria-label="Search" />';
$showLabel = $params->get('show_label', 1);
$labelClass = (!$showLabel ? 'visually-hidden ' : '') . 'finder';
$label = '<label for="mod-finder-searchword' . $module->id . '" class="text-center text-whit pt-4 d-none d-sm-block h4 ' . $labelClass . '">' . $params->get('alt_label', Text::_('JSEARCH_FILTER_SUBMIT')) . '</label>';
$output = '';
if ($params->get('show_button', 0))
{
$output .= $label;
$output .= '<div class="mod-finder__search input-group">';
$output .= $input;
$output .= '<button class="btn btn-primary" type="submit"><span class="icon-search icon-black" aria-hidden="true"></span> ' . Text::_('JSEARCH_FILTER_SUBMIT') . '</button>';
$output .= '</div>';
}
else
{
$output .= $label;
$output .= $input;
}
Text::script('MOD_FINDER_SEARCH_VALUE', true);
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $app->getDocument()->getWebAssetManager();
$wa->getRegistry()->addExtensionRegistryFile('com_finder');
/*
* This segment of code sets up the autocompleter.
*/
if ($params->get('show_autosuggest', 1))
{
$wa->usePreset('awesomplete');
$app->getDocument()->addScriptOptions('finder-search', array('url' => Route::_('index.php?option=com_finder&task=suggestions.suggest&format=json&tmpl=component')));
}
$wa->useScript('com_finder.finder');
?>
<form class="mx-auto form-control-lg w-75 mod-finder js-finder-searchform form-search" action="<?php echo Route::_($route); ?>" method="get" role="search">
<?php echo $output; ?>
<?php $show_advanced = $params->get('show_advanced', 0); ?>
<?php if ($show_advanced == 2) : ?>
<br>
<a href="<?php echo Route::_($route); ?>" class="mod-finder__advanced-link"><?php echo Text::_('COM_FINDER_ADVANCED_SEARCH'); ?></a>
<?php elseif ($show_advanced == 1) : ?>
<div class="mod-finder__advanced js-finder-advanced">
<?php echo HTMLHelper::_('filter.select', $query, $params); ?>
</div>
<?php endif; ?>
<?php echo FinderHelper::getGetFields($route, (int) $params->get('set_itemid', 0)); ?>
</form>
The knowledge base
PhP markup categories/default_items.php
<?php
/**
* @package Joomla.Site
* @subpackage com_content
* @author web-eau.net
* @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
use Joomla\Component\Content\Site\Helper\RouteHelper;
if ($this->maxLevelcat != 0 && count($this->items[$this->parent->id]) > 0) :
?>
<div class="row com-content-categories__items">
<?php foreach ($this->items[$this->parent->id] as $id => $item) : ?>
<div class="col-lg-4 col-sm-12">
<?php if ($this->params->get('show_empty_categories_cat') || $item->numitems || count($item->getChildren())) : ?>
<div class="p-3 m-3 com-content-categories__ite">
<div class="com-content-categories__item-title-wrapper">
<div class="com-content-categories__item-title">
<h3 class="page-header item-title">
<i class="bleu fas fa-folder me-2"></i><a class="bleu" href="<?php echo Route::_(RouteHelper::getCategoryRoute($item->id, $item->language)); ?>">
<?php echo $this->escape($item->title); ?></a>
</h3>
<?php if ($this->params->get('show_cat_num_articles_cat') == 1) :?>
<span class="small">
<?php echo Text::_('COM_CONTENT_NUM_ITEMS'); ?>
<?php echo $item->numitems; ?>
</span>
<!--<br />
<span class="nombre-articles">
<?php echo $item->numitems; ?>
<?php echo JText::_('COM_CONTENT_NUM_ITEMS'); ?>
</span>-->
<?php endif; ?>
</div>
<?php if (count($item->getChildren()) > 0 && $this->maxLevelcat > 1) : ?>
<button
type="button"
id="category-btn-<?php echo $item->id; ?>"
data-category-id="<?php echo $item->id; ?>"
class="btn btn-secondary btn-sm"
aria-expanded="false"
aria-label="<?php echo Text::_('JGLOBAL_EXPAND_CATEGORIES'); ?>"
>
<span class="icon-plus" aria-hidden="true"></span>
</button>
<?php endif; ?>
</div>
<?php if ($this->params->get('show_description_image') && $item->getParams()->get('image')) : ?>
<img src="<?php echo $item->getParams()->get('image'); ?>" alt="<?php echo htmlspecialchars($item->getParams()->get('image_alt'), ENT_COMPAT, 'UTF-8'); ?>">
<?php endif; ?>
<?php if ($this->params->get('show_subcat_desc_cat') == 1) : ?>
<?php if ($item->description) : ?>
<div class="com-content-categories__description category-desc">
<?php echo HTMLHelper::_('content.prepare', $item->description, '', 'com_content.categories'); ?>
</div>
<?php endif; ?>
<?php endif; ?>
<?php if (count($item->getChildren()) > 0 && $this->maxLevelcat > 1) : ?>
<div class="com-content-categories__children" id="category-<?php echo $item->id; ?>" hidden="">
<?php
$this->items[$item->id] = $item->getChildren();
$this->parent = $item;
$this->maxLevelcat--;
echo $this->loadTemplate('items');
$this->parent = $item->getParent();
$this->maxLevelcat++;
?>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
PhP markup category/blog.php
<?php
/**
* @package Joomla.Site
* @subpackage com_content
* @author web-eau.net
* @copyright (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\FileLayout;
use Joomla\CMS\Layout\LayoutHelper;
$app = Factory::getApplication();
$this->category->text = $this->category->description;
$app->triggerEvent('onContentPrepare', array($this->category->extension . '.categories', &$this->category, &$this->params, 0));
$this->category->description = $this->category->text;
$results = $app->triggerEvent('onContentAfterTitle', array($this->category->extension . '.categories', &$this->category, &$this->params, 0));
$afterDisplayTitle = trim(implode("\n", $results));
$results = $app->triggerEvent('onContentBeforeDisplay', array($this->category->extension . '.categories', &$this->category, &$this->params, 0));
$beforeDisplayContent = trim(implode("\n", $results));
$results = $app->triggerEvent('onContentAfterDisplay', array($this->category->extension . '.categories', &$this->category, &$this->params, 0));
$afterDisplayContent = trim(implode("\n", $results));
$htag = $this->params->get('show_page_heading') ? 'h2' : 'h1';
?>
<div class="p-4 com-content-category-blog blog" itemscope itemtype="https://schema.org/Blog">
<?php if ($this->params->get('show_page_heading')) : ?>
<div class="page-header">
<h1> <?php echo $this->escape($this->params->get('page_heading')); ?> </h1>
</div>
<?php endif; ?>
<?php if ($this->params->get('show_category_title', 1)) : ?>
<<?php echo $htag; ?>>
<h1 class="bleu">
<span class="subheading-category"><i class="fas fa-book-open mr-2"></i>
<?php echo $this->category->title; ?></span>
</h1>
</<?php echo $htag; ?>>
<?php endif; ?>
<?php echo $afterDisplayTitle; ?>
<?php if ($this->params->get('show_cat_tags', 1) && !empty($this->category->tags->itemTags)) : ?>
<?php $this->category->tagLayout = new FileLayout('joomla.content.tags'); ?>
<?php echo $this->category->tagLayout->render($this->category->tags->itemTags); ?>
<?php endif; ?>
<?php if ($beforeDisplayContent || $afterDisplayContent || $this->params->get('show_description', 1) || $this->params->def('show_description_image', 1)) : ?>
<div class="category-desc clearfix mb-4">
<?php if ($this->params->get('show_description_image') && $this->category->getParams()->get('image')) : ?>
<?php echo LayoutHelper::render(
'joomla.html.image',
[
'src' => $this->category->getParams()->get('image'),
'alt' => empty($this->category->getParams()->get('image_alt')) && empty($this->category->getParams()->get('image_alt_empty')) ? false : $this->category->getParams()->get('image_alt'),
]
); ?>
<?php endif; ?>
<?php echo $beforeDisplayContent; ?>
<?php if ($this->params->get('show_description') && $this->category->description) : ?>
<span class="fs-5"><?php echo HTMLHelper::_('content.prepare', $this->category->description, '', 'com_content.category'); ?></span>
<?php endif; ?>
<?php echo $afterDisplayContent; ?>
</div>
<?php endif; ?>
<?php if (empty($this->lead_items) && empty($this->link_items) && empty($this->intro_items)) : ?>
<?php if ($this->params->get('show_no_articles', 1)) : ?>
<div class="alert alert-info">
<span class="icon-info-circle" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('INFO'); ?></span>
<?php echo Text::_('COM_CONTENT_NO_ARTICLES'); ?>
</div>
<?php endif; ?>
<?php endif; ?>
<?php $leadingcount = 0; ?>
<?php if (!empty($this->lead_items)) : ?>
<div class="com-content-category-blog__items blog-items items-leading <?php echo $this->params->get('blog_class_leading'); ?>">
<?php foreach ($this->lead_items as &$item) : ?>
<div class="pl-2 py-4 com-content-category-blog__item blog-item" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<?php
$this->item = &$item;
echo $this->loadTemplate('item');
?>
</div>
<?php $leadingcount++; ?>
<?php endforeach; ?>
</div><br />
<?php endif; ?>
<?php
$introcount = count($this->intro_items);
$counter = 0;
?>
<?php if (!empty($this->intro_items)) : ?>
<?php $blogClass = $this->params->get('blog_class', ''); ?>
<?php if ((int) $this->params->get('num_columns') > 1) : ?>
<?php $blogClass .= (int) $this->params->get('multi_column_order', 0) === 0 ? ' masonry-' : ' columns-'; ?>
<?php $blogClass .= (int) $this->params->get('num_columns'); ?>
<?php endif; ?>
<div class="col-container com-content-category-blog__items blog-items <?php echo $blogClass; ?>">
<?php foreach ($this->intro_items as $key => &$item) : ?>
<div class="p-4 item-kb com-content-category-blog__item blog-item"
itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<?php
$this->item = & $item;
echo $this->loadTemplate('item');
?>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php if (!empty($this->link_items)) : ?>
<div class="items-more">
<?php echo $this->loadTemplate('links'); ?>
</div>
<?php endif; ?>
<?php if ($this->maxLevel != 0 && !empty($this->children[$this->category->id])) : ?>
<div class="com-content-category-blog__children cat-children">
<?php if ($this->params->get('show_category_heading_title_text', 1) == 1) : ?>
<h3> <?php echo Text::_('JGLOBAL_SUBCATEGORIES'); ?> </h3>
<?php endif; ?>
<?php echo $this->loadTemplate('children'); ?> </div>
<?php endif; ?>
<?php if (($this->params->def('show_pagination', 1) == 1 || ($this->params->get('show_pagination') == 2)) && ($this->pagination->pagesTotal > 1)) : ?>
<div class="com-content-category-blog__navigation w-100">
<?php if ($this->params->def('show_pagination_results', 1)) : ?>
<p class="com-content-category-blog__counter counter float-end pt-3 pe-2">
<?php echo $this->pagination->getPagesCounter(); ?>
</p>
<?php endif; ?>
<div class="com-content-category-blog__pagination">
<?php echo $this->pagination->getPagesLinks(); ?>
</div>
</div>
<?php endif; ?>
</div>
CSS
.small {
font-size:0.75em;
color:#C0C0C0;
}
.bleu {
color:#145889;
}
.col-container {
display: table;width: 100%;
}
.item-kb {
display: table-cell;
}