Недавно у меня возникла необходимость для модуля у которого много настроек сделать так что бы настройки были не распиханы по куче закладок, а отображались поля в зависимости от нужного отображения модуля!

Можно было пойти тремя путями:

  1. создать все все поля, и скриптами скрывать в зависимости от того какое поле выбрано, недостаток подобного метода что при добавлении новой группы полей придется в скрипте каждый раз дописывать какие поля скрывать, но этот метод самый простой
  2. создавать поля вручную и подгружать их через AJAX. Недостаток такого метода в том что каждое поле придется описывать в HTML разметке, что не очень удобно
  3. подгружать поля AJAX c использованием механизма форм Joomla JForm,

Так как мы не ищем легких путей то мы пойдем самым сложным третьим вариантом! Плюсы этого варианта в том что мы сможем делать формы в XML виде, и делать их очень быстро!

Итак для начала нам нужно будет создать каркас для модуля, и для этого вы можете воспользоваться моим сервисом

После создания модуля вам нужно в папке с модулем создать следующие папки и файлы:

Структура папок и файлов модуля

папка fields - в ней будет содержаться файл с нашим полем, а так же папка для хранения xml файлов формы которые будут загружаться динамически

папка fields/forms - в ней лежат наши XML файлы разных вариантов формы которую мы будем загружать

fields/ajax.php - файл с классом поля

layouts/field.php - файл отображения поля HTML данных поля

form.php - файл с подключенным фреймворком в котором и будут JForm рендерить нужный XML файл и вносить в него данные из модуля!

Итак сначала мы опишем класс нашего поля в файле fields/ajax.php, тут все предельно просто:

defined( '_JEXEC' ) or die;
class JFormFieldAjax extends JFormField
{
	protected $type = 'Ajax';

	protected function getInput()
	{
		return JLayoutHelper::render( 'field', $this->form->getValue( 'id' ), JPATH_ROOT . '/modules/mod_test/layouts/' );
	}
}

Мы создаем свое произвольное поле, и выводим его через механизм JLayout, поле лежит в папке /modules/mod_test/layouts/, и в качестве параметра передаем $this->form->getValue( 'id' ), в этом поле хранится id текущего модуля, и необходимо оно для того что бы получать параметры модуля из базы.

Выводим наше поле в параметрах модуля, для этого открываем файл mod_test.xml и в секции <fields name="params"> добавляем:

Что тут мы добавили? Во первых путь к нашему новому полю: addfieldpath="modules/mod_test/fields/", во вторых поле layout в котором мы выбираем какую форму грузить, значение value в варианте загружаемой формы должно совпадать с именем XML формы в папке fields/forms, и в третьих мы вывели само поле нашей формы с именем setup! Имя поля важно, оно будет использоваться и для сохранения данных и для обработки в аякс запросе, и везде оно должно быть одинаковым!

Дальше мы создаем формы, в формах вы можете создавать какие угодно стандартные типы полей, но с ними надо быть очень аккуратными, ибо поля которые выполняют какие действия, например поле media, которое служит для выбора изображения, потребует дополнительной инициализации в слое! Пример формы


Самое интересное на что тут нужно обратить это название поля, а название поля у нас например такое: setup][param1, нет ошибок тут нет, поле так и должно называться, первое как я и говорил это название поля: setup, дальше фигруные скобочки ][ и уже название текущего поля которое вы можете делать какое угодно! Так же нам нужно поля размещать все поля в секции <fields name="params">

Теперь мы опишем слой вывода поля в файле layouts/field.php

<?php
defined( '_JEXEC' ) or die;
JHtml::_( 'jquery.framework' );
JHtml::_( 'bootstrap.tooltip' );
JHtml::_( 'behavior.multiselect' );
JHtml::_( 'formbehavior.chosen', 'select' );
?>

В этом файле у нас подключение библиотеки JQuery и библиотек для отображения списков стилизованных и подсказок для поля, на тот случай если они не подключены

А так же там небольшой JQuery скрипт который делает ajax запрос в файл form.php, и после того как вставит полученную форму в блок с id="fieldsModuleWrapper" инициализирует нужные скрипты для загруженных полей!

Все что нам осталось это описать файл form.php:

<?php
//Подкючение Joomla Framework
define( '_JEXEC', 1 );
if ( file_exists( __DIR__ . '/defines.php' ) ) {
	include_once __DIR__ . '/defines.php';
}
if ( !defined( '_JDEFINES' ) ) {
	define( 'JPATH_BASE', __DIR__ . '/../../' );
	require_once JPATH_BASE . '/includes/defines.php';
}
require_once JPATH_BASE . '/includes/framework.php';
//Подкючение Joomla Framework окончание

//Получаем объект JInput для работы с пользовательским вводров
$input = JFactory::getApplication( 'site' )->input;
//Получаем объект для работы с базой данных
$db = JFactory::getDbo();
//Запрос на получения парамета модуля по ID из $_REQUEST
$query = $db->getQuery( true )
	->select( 'params' )
	->from( '#__modules' )
	->where( 'id=' . (int)$input->getInt( 'id', 0 ) );
//Получаем параметры
$formParams = new \Joomla\Registry\Registry( $db->setQuery( $query )->loadResult() );
try {
	//Создаем форму
	$form = JForm::getInstance(
		'jform',
		JPATH_ROOT . '/modules/mod_test/fields/forms/' . $input->getCmd( 'layout', '' ) . '.xml',
		[ 'control' => 'jform', 'load_data' => true ]
	);
	//получаем значения полей
	$data = (array)$formParams->get( 'setup' );
	//в цикле проходим все поля в группе params и устанавливаем в них значение
	//из параметров модуля
	foreach ( $data as $key => $value ) {
		$form->setValue( 'setup][' . $key, 'params', $value );
	}
	//Выводим поля из группы params
	foreach ( $form->getGroup( 'params' ) as $field ) {
		echo $field->getControlGroup();
	}

} catch ( Exception $ex ) {

}
exit;

Все что делает этот файл описано в комментариях в самом коде

Пример работы этого поля в админке:

Пример отображения поля в админке

P.S. как использовать это поле в пользовательской части? Да легко в точке входа модуля mod_test.php добавить следующий код:

$setups = new \Joomla\Registry\Registry( $params->get( 'setup' ) );
$params->merge( $setups );

Дальше ваши параметры будут доступны через $params->get('param_name);

Скачать пример модуля