콘텐츠로 이동

블록 개발

블록은 테마 사이드바와 콘텐츠 영역에 표시되는 재사용 가능한 콘텐츠 위젯입니다. 이 가이드에서는 XOOPS 블록 생성, 구성 및 사용자 정의를 다룹니다.

$modversion['blocks'][] = [
'file' => 'blocks/recent.php',
'name' => '_MI_MYMODULE_BLOCK_RECENT',
'description' => '_MI_MYMODULE_BLOCK_RECENT_DESC',
'show_func' => 'mymodule_recent_show',
'edit_func' => 'mymodule_recent_edit',
'template' => 'mymodule_block_recent.tpl',
'options' => '10|0|date', // Default options: limit|category|sort
];
매개변수설명
file블록 함수가 포함된 PHP 파일
name블록 제목의 언어 상수
description설명을 위한 언어 상수
show_func블록 내용을 렌더링하는 기능
edit_func블록 옵션 양식을 렌더링하는 기능
templateSmarty 템플릿 파일
options파이프로 구분된 기본 옵션
blocks/recent.php
function mymodule_recent_show(array $options): array
{
// Parse options
$limit = (int) ($options[0] ?? 10);
$categoryId = (int) ($options[1] ?? 0);
$sortBy = $options[2] ?? 'date';
// Get module helper
$helper = \Xmf\Module\Helper::getHelper('mymodule');
$handler = $helper->getHandler('Item');
// Build criteria
$criteria = new \CriteriaCompo();
$criteria->add(new \Criteria('status', 'published'));
if ($categoryId > 0) {
$criteria->add(new \Criteria('category_id', $categoryId));
}
$criteria->setSort($sortBy === 'popular' ? 'views' : 'created_at');
$criteria->setOrder('DESC');
$criteria->setLimit($limit);
// Fetch items
$items = $handler->getObjects($criteria);
// Build block array
$block = [];
foreach ($items as $item) {
$block['items'][] = [
'id' => $item->getVar('id'),
'title' => $item->getVar('title'),
'link' => $helper->url("item.php?id=" . $item->getVar('id')),
'date' => formatTimestamp($item->getVar('created_at'), 's'),
'summary' => $item->getVar('summary'),
'views' => $item->getVar('views'),
];
}
$block['show_summary'] = $helper->getConfig('block_show_summary');
return $block;
}
function mymodule_recent_edit(array $options): string
{
$helper = \Xmf\Module\Helper::getHelper('mymodule');
// Option 1: Number of items
$form = _MI_MYMODULE_BLOCK_LIMIT . ': ';
$form .= '<input type="text" name="options[0]" value="' . ($options[0] ?? 10) . '" size="5">';
$form .= '<br>';
// Option 2: Category select
$form .= _MI_MYMODULE_BLOCK_CATEGORY . ': ';
$form .= '<select name="options[1]">';
$form .= '<option value="0">' . _ALL . '</option>';
$categoryHandler = $helper->getHandler('Category');
$categories = $categoryHandler->getObjects();
foreach ($categories as $cat) {
$selected = ($cat->getVar('id') == ($options[1] ?? 0)) ? ' selected' : '';
$form .= '<option value="' . $cat->getVar('id') . '"' . $selected . '>';
$form .= $cat->getVar('name') . '</option>';
}
$form .= '</select><br>';
// Option 3: Sort order
$form .= _MI_MYMODULE_BLOCK_SORT . ': ';
$form .= '<select name="options[2]">';
$sortOptions = ['date' => _MI_MYMODULE_SORT_DATE, 'popular' => _MI_MYMODULE_SORT_POPULAR];
foreach ($sortOptions as $value => $label) {
$selected = ($value == ($options[2] ?? 'date')) ? ' selected' : '';
$form .= '<option value="' . $value . '"' . $selected . '>' . $label . '</option>';
}
$form .= '</select>';
return $form;
}
{* templates/blocks/mymodule_block_recent.tpl *}
<div class="mymodule-block-recent">
<{if $block.items}>
<ul class="item-list">
<{foreach item=item from=$block.items}>
<li class="item">
<a href="<{$item.link}>" class="item-title">
<{$item.title}>
</a>
<{if $block.show_summary && $item.summary}>
<p class="item-summary"><{$item.summary|truncate:100}></p>
<{/if}>
<span class="item-meta">
<span class="date"><{$item.date}></span>
<span class="views"><{$item.views}> views</span>
</span>
</li>
<{/foreach}>
</ul>
<{else}>
<p class="no-items"><{$smarty.const._MI_MYMODULE_NO_ITEMS}></p>
<{/if}>
</div>

복제 가능한 블록은 여러 인스턴스를 허용합니다.

$modversion['blocks'][] = [
'file' => 'blocks/category.php',
'name' => '_MI_MYMODULE_BLOCK_CATEGORY',
'description' => '_MI_MYMODULE_BLOCK_CATEGORY_DESC',
'show_func' => 'mymodule_category_show',
'edit_func' => 'mymodule_category_edit',
'template' => 'mymodule_block_category.tpl',
'options' => '0',
'can_clone' => true, // Enable cloning
];
function mymodule_ajax_show(array $options): array
{
$block = [
'block_id' => $options['bid'] ?? 0,
'ajax_url' => XOOPS_URL . '/modules/mymodule/ajax/block.php',
'interval' => (int) ($options[0] ?? 30), // Refresh interval in seconds
];
return $block;
}
{* Template with AJAX refresh *}
<div id="mymodule-block-<{$block.block_id}>" class="ajax-block">
<div class="block-content"></div>
</div>
<script>
(function() {
const container = document.getElementById('mymodule-block-<{$block.block_id}>');
const url = '<{$block.ajax_url}>?bid=<{$block.block_id}>';
function loadContent() {
fetch(url)
.then(response => response.text())
.then(html => {
container.querySelector('.block-content').innerHTML = html;
});
}
loadContent();
setInterval(loadContent, <{$block.interval}> * 1000);
})();
</script>
  1. 캐시 결과 - 비용이 많이 드는 쿼리를 캐시합니다.
  2. 옵션 유효성 검사 - 항상 블록 옵션 유효성을 검사합니다.
  3. 이스케이프 출력 - 모든 사용자 콘텐츠를 삭제합니다.
  4. Criteria 사용 - Criteria 클래스를 사용하여 쿼리 작성
  5. 쿼리 제한 - 성능에 대한 합리적인 제한 설정
  6. 반응형 템플릿 - 모바일에서 블록이 작동하는지 확인
  • 모듈 개발 - 모듈 생성 가이드 -../02-Core-Concepts/Templates/Smarty-Templating - 템플릿 구문 -../04-API-참조/템플릿/템플릿-시스템 - XOOPS 템플릿 엔진
  • xoops_version.php - 모듈 매니페스트