В данном посте я дам вам минимум информации, которой хватит для создания своего модуля для системы OpenCart. Ничего лишнего, итак приступим

Для того что бы создать свой первый модуль, нам необходимо как минимум 6 файлов. Пускай наш новый модуль будет иметь название  ”myModul” и для его работы нам понадобятся следующие файлы:

  1. файл представления модуля: catalog\view\theme\default\template\module\myModul.tpl
  2. контроллер модуля: catalog\controller\module\myModul.php
  3. языковой файл: catalog\language\russian\module\myModul.php
  4. файл представления модуля для админпанели: admin\view\template\module\myModul.tpl
  5. контроллер модуля для админпанели: admin\controller\module\myModul.php
  6. языковой файл модуля для админпанели: admin\language\russian\module\myModul.php

Создавать мы их будем в порядке нумерации.

 

Создадим catalog\view\theme\default\template\module\myModul.tpl, и наполним его следующим содержимым:

<div class="box">
  <div class="box-heading"><?php echo $heading_title; ?></div>
  <div class="box-content">
		код модуля
  </div>
</div>

Это базовая структура модулей для CMS OpenCart, вы можете написать любую свою.

Если оставить данный код без изменений, то наш модуль будет выглядеть так:

1

 

2. Контроллер модуля

Аналогично, создаем catalog\controller\module\myModul.php и наполняем его следующим минимум:

<?php  
class ControllerModuleMyModul extends Controller {
	protected function index() {

		if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/module/myModul.tpl')) {
			$this->template = $this->config->get('config_template') . '/template/module/myModul.tpl';
		} else {
			$this->template = 'default/template/module/myModul.tpl';
		}		
		$this->render();
	}
}
?>

Заметьте название класса «ControllerModuleMyModul» это строка «ControllerModule» плюс «имя модуля с большой буквы». В контроллере мы как минимум должны, указать какой файл представления будет отвечать за вывод информации. Но данный контроллер не функционален, это всего лишь заготовка. Функционалом он будет заполняться в зависимости от потребностей модуля.

 

Как пример, в нем вы можете подключать модель:

$this->load->model('директория_с_моделью/имя_модели');

и далее вызывать ее методы.

Также можно подключать языковой файл:

$this->language->load('module/имя_языкового_файла');

и объявлять переменные:

$this->data['имя_переменной'] = $this->language->get('имя_переменной_из_яз_файла');

Данная переменная будет видна в шаблоне myModul.tpl.

 

3. Языковой файл

Создаем catalog\language\russian\module\myModul.php и наполняем его следующим содержимым:

<?php
$_['имя_переменной'] = 'значение переменной';
?>

Мы можем работать с данной переменной, только в том случае если в контроллере объявим:

$this->language->load('module/myModul');

обращаться к ней следует так

$this->language->get('имя_переменной');

Вообщем наполняем языковой файл переменными, которые будут хранить текстовую информацию, необходимую для нашего модуля. Это может быть строка «Заголовок», например:

2

 

4. Файл представления модуля для админпанели

Создаем admin\view\template\module\myModul.tpl и наполняем его следующим содержимым:

<?php echo $header; ?>
<div id="content">
  <div class="breadcrumb">
    <?php foreach ($breadcrumbs as $breadcrumb) { ?>
    <?php echo $breadcrumb['separator']; ?>
	<a href="/<?php echo $breadcrumb['href']; ?>">
		<?php echo $breadcrumb['text']; ?>
	</a>
    <?php } ?>
  </div>
  <?php if ($error_warning) { ?>
  <div class="warning"><?php echo $error_warning; ?></div>
  <?php } ?>
  <div class="box">
    <div class="heading">
		<h1>
			<img src="/view/image/module.png" alt="" /> 
			<?php echo $heading_title; ?>
		</h1>
		<div class="buttons">
			<a onclick="$('#form').submit();" class="button">
				<?php echo $button_save; ?>
			</a>
			<a onclick="location = '<?php echo $cancel; ?>';" class="button">
				<?php echo $button_cancel; ?>
			</a>
		</div>
    </div>
    <div class="content">
      <form action="<?php echo $action; ?>" 
			method="post" 
			enctype="multipart/form-data" 
			id="form"
		>
        <table id="module" class="list">
          <thead>
            <tr>
              <td class="left"><?php echo $entry_layout; ?></td>
              <td class="left"><?php echo $entry_position; ?></td>
              <td class="left"><?php echo $entry_status; ?></td>
              <td class="right"><?php echo $entry_sort_order; ?></td>
              <td></td>
            </tr>
          </thead>
          <?php $module_row = 0; ?>
          <?php foreach ($modules as $module) { ?>
          <tbody id="module-row<?php echo $module_row; ?>">
            <tr>
				<td class="left">
					<select name="myModul_module[<?php echo $module_row; ?>][layout_id]">
					  <?php foreach ($layouts as $layout) { ?>
					  <?php if ($layout['layout_id'] == $module['layout_id']) { ?>
						<option value="<?php echo $layout['layout_id']; ?>" selected="selected">
							<?php echo $layout['name']; ?>
						</option>
					  <?php } else { ?>
						<option value="<?php echo $layout['layout_id']; ?>">
							<?php echo $layout['name']; ?>
						</option>
					  <?php } ?>
					  <?php } ?>
					</select>
				</td>
				 <td class="left">
					<select name="myModul_module[<?php echo $module_row; ?>][position]">
						<?php if ($module['position'] == 'content_top') { ?>
						<option value="content_top" selected="selected">
							<?php echo $text_content_top; ?>
						</option>
						<?php } else { ?>
						<option value="content_top">
							<?php echo $text_content_top; ?>
						</option>
						<?php } ?>
						<?php if ($module['position'] == 'content_bottom') { ?>
						<option value="content_bottom" selected="selected">
								<?php echo $text_content_bottom; ?>
						</option>
						<?php } else { ?>
						<option value="content_bottom">
							<?php echo $text_content_bottom; ?>
						</option>
						<?php } ?>
						<?php if ($module['position'] == 'column_left') { ?>
						<option value="column_left" selected="selected">
							<?php echo $text_column_left; ?>
						</option>
						<?php } else { ?>
						<option value="column_left">
							<?php echo $text_column_left; ?>
						</option>
						<?php } ?>
						<?php if ($module['position'] == 'column_right') { ?>
						<option value="column_right" selected="selected">
							<?php echo $text_column_right; ?>
						</option>
						<?php } else { ?>
						<option value="column_right">
							<?php echo $text_column_right; ?>
						</option>
						<?php } ?>
					</select>
				</td>
              <td class="left"><select name="myModul_module[<?php echo $module_row; ?>][status]">
                  <?php if ($module['status']) { ?>
                  <option value="1" selected="selected"><?php echo $text_enabled; ?></option>
                  <option value="0"><?php echo $text_disabled; ?></option>
                  <?php } else { ?>
                  <option value="1"><?php echo $text_enabled; ?></option>
                  <option value="0" selected="selected"><?php echo $text_disabled; ?></option>
                  <?php } ?>
                </select></td>
				<td class="right">
					<input 
							type="text" 
							name="myModul_module[<?php echo $module_row; ?>][sort_order]" 
							value="<?php echo $module['sort_order']; ?>" 
							size="3" 
					/>
				</td>
				<td class="left">
					<a onclick="$('#module-row<?php echo $module_row; ?>').remove();" class="button">
						<?php echo $button_remove; ?>
					</a>
				</td>
            </tr>
          </tbody>
          <?php $module_row++; ?>
          <?php } ?>
          <tfoot>
            <tr>
				<td colspan="4"></td>
				<td class="left">	
					<a onclick="addModule();" class="button">
						<?php echo $button_add_module; ?>
					</a>
				</td>
            </tr>
          </tfoot>
        </table>
      </form>
    </div>
  </div>
</div>
<script type="text/javascript"><!--
var module_row = <?php echo $module_row; ?>;

function addModule() {	
	html  = '<tbody id="module-row' + module_row + '">';
	html += '  <tr>';
	html += '    <td class="left"><select name="myModul_module[' + module_row + '][layout_id]">';
	<?php foreach ($layouts as $layout) { ?>
	html += '      <option value="<?php echo $layout['layout_id']; ?>">'+
					'<?php echo addslashes($layout['name']); ?></option>';
	<?php } ?>
	html += '    </select></td>';
	html += '    <td class="left"><select name="myModul_module[' + module_row + '][position]">';
	html += '      <option value="content_top"><?php echo $text_content_top; ?></option>';
	html += '      <option value="content_bottom"><?php echo $text_content_bottom; ?></option>';
	html += '      <option value="column_left"><?php echo $text_column_left; ?></option>';
	html += '      <option value="column_right"><?php echo $text_column_right; ?></option>';
	html += '    </select></td>';
	html += '    <td class="left"><select name="myModul_module[' + module_row + '][status]">';
    html += '      <option value="1" selected="selected"><?php echo $text_enabled; ?></option>';
    html += '      <option value="0"><?php echo $text_disabled; ?></option>';
    html += '    </select></td>';
	html += '    <td class="right"><input type="text" name="myModul_module[' + 
							module_row + '][sort_order]" value="" size="3" /></td>';
	html += '    <td class="left"><a onclick="$(\'#module-row' + module_row + '\').remove();"'+
								' class="button"><?php echo $button_remove; ?></a></td>';
	html += '  </tr>';
	html += '</tbody>';

	$('#module tfoot').before(html);

	module_row++;
}
//--></script> 
<?php echo $footer; ?>

Данный код был взят из файла представления для  модуля «Информация» (admin\view\template\module\information.tpl),  я заменил только «information» на «myModul».

Данный код отображает следующие возможности в админпанели по настройки модуля:

3

Файл представления для админпанели, вы можете наполнить своим содержимым. Я представил этот пример только из-за того, что он хорошо предоставляет минимальные настройки для модуля (т.е. выбор схемы и положения модуля).

 

5. Контролер модуля для админпанели

Создаем admin\controller\module\myModul.php и наполняем его содержимым контроллера модуля которого мы брали в качестве образца.

Например, наполним его содержимым контроллера модуля «Информация» (controller\module\information.php).

<?php
class ControllerModuleMyModul extends Controller {
	private $error = array(); 

	public function index() {   
		$this->load->language('module/myModul');
		$this->document->setTitle($this->language->get('heading_title'));
		$this->load->model('setting/setting');

		if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
			$this->model_setting_setting->editSetting('myModul', $this->request->post);		

			$this->session->data['success'] = $this->language->get('text_success');

			$this->redirect(
								$this->url->link('extension/module', 'token=' . 
								$this->session->data['token'], 'SSL')
							);
		}

		$this->data['heading_title'] = $this->language->get('heading_title');

		$this->data['text_enabled'] = $this->language->get('text_enabled');
		$this->data['text_disabled'] = $this->language->get('text_disabled');
		$this->data['text_content_top'] = $this->language->get('text_content_top');
		$this->data['text_content_bottom'] = $this->language->get('text_content_bottom');		
		$this->data['text_column_left'] = $this->language->get('text_column_left');
		$this->data['text_column_right'] = $this->language->get('text_column_right');

		$this->data['entry_layout'] = $this->language->get('entry_layout');
		$this->data['entry_position'] = $this->language->get('entry_position');
		$this->data['entry_status'] = $this->language->get('entry_status');
		$this->data['entry_sort_order'] = $this->language->get('entry_sort_order');

		$this->data['button_save'] = $this->language->get('button_save');
		$this->data['button_cancel'] = $this->language->get('button_cancel');
		$this->data['button_add_module'] = $this->language->get('button_add_module');
		$this->data['button_remove'] = $this->language->get('button_remove');

 		if (isset($this->error['warning'])) {
			$this->data['error_warning'] = $this->error['warning'];
		} else {
			$this->data['error_warning'] = '';
		}

  		$this->data['breadcrumbs'] = array();

   		$this->data['breadcrumbs'][] = array(
       		'text'      => $this->language->get('text_home'),
			'href'      => $this->url->link('common/home', 'token=' . 
							$this->session->data['token'], 'SSL'),
      		'separator' => false
   		);

   		$this->data['breadcrumbs'][] = array(
       		'text'      => $this->language->get('text_module'),
			'href'      => $this->url->link('extension/module', 'token=' . 
							$this->session->data['token'], 'SSL'),
      		'separator' => ' :: '
   		);

   		$this->data['breadcrumbs'][] = array(
       		'text'      => $this->language->get('heading_title'),
			'href'      => $this->url->link('module/myModul', 'token=' . 
							$this->session->data['token'], 'SSL'),
      		'separator' => ' :: '
   		);

		$this->data['action'] = $this->url->link('module/myModul', 'token=' . 
								$this->session->data['token'], 'SSL');

		$this->data['cancel'] = $this->url->link('extension/module', 'token=' . 
								$this->session->data['token'], 'SSL');

		$this->data['modules'] = array();

		if (isset($this->request->post['myModul_module'])) {
			$this->data['modules'] = $this->request->post['myModul_module'];
		} elseif ($this->config->get('myModul_module')) { 
			$this->data['modules'] = $this->config->get('myModul_module');
		}				
		$this->load->model('design/layout');

		$this->data['layouts'] = $this->model_design_layout->getLayouts();

		$this->template = 'module/myModul.tpl';
		$this->children = array(
			'common/header',
			'common/footer'
		);				
		$this->response->setOutput($this->render());
	}

	private function validate() {
		if (!$this->user->hasPermission('modify', 'module/myModul')) {
			$this->error['warning'] = $this->language->get('error_permission');
		}

		if (!$this->error) {
			return true;
		} else {
			return false;
		}	
	}
}
?>

Единственное что я здесь изменил по отношению к оригинальному файлу, так это то, что произвел замену в имени класса с «ControllerModuleInformation» на «ControllerModuleMyModul» и все упоминания слова «information» заменил на «myModul».

Каков ваш контроллер, будет зависеть от предоставляемого функционала настроек, который предлагает ваш файл представления для админпанели (т.е. «admin\view\template\module\myModul.tpl»).

 

6. Языковой файл модуля для админпанели

Создаем admin\language\russian\module\myModul.php, наполняем его:

<?php
// Heading
$_['heading_title']       = 'myModul';

// Text
$_['text_module']         = 'Модули';
$_['text_success']        = 'Настройки модуля обновлены!';
$_['text_content_top']    = 'Верх страницы';
$_['text_content_bottom'] = 'Низ страницы';
$_['text_column_left']    = 'Левая колонка';
$_['text_column_right']   = 'Правая колонка';

// Entry
$_['entry_layout']        = 'Схема:';
$_['entry_position']      = 'Расположение:';
$_['entry_status']        = 'Статус:';
$_['entry_sort_order']    = 'Порядок сортировки:';

// Error
$_['error_permission']    = 'У Вас нет прав для управления этим модулем!';
?>

Содержимое данного файла, я опять таки взял из образца для модуля «Информация». Тут главное определиться с содержимым переменных, который использует ваш файл представления для админпанели (admin\view\template\module\myModul.tpl).

Итог

Теперь если вы зайдете в Дополнения->Модули вы обнаружите модуль «myModul», с ним можно работать как с любым другим модулем, его можно установливать/удалять, определять положение на странице и т.п.


Добавлено позже

Со временем у меня возник вопрос :

- А как добавить в настройках моего модуля свои параметры?

Например я хочу что-бы в настройках модуля был “мой параметр”

module my options

И он был виден в tpl файле модуля.

Сначала я рассмотрю механизм работы настроек для модуля в OpenCart, а далее расскажу по шагам как добавить свой параметр (жмите для перехода в данный раздел)

Механизм работы

Сначала, рассмотрим каков механизм работы

Когда в настройках модуля вы нажимаете на «SAVE” или “Сохранить”, вы тем самым посылаете POST запрос в контролер модуля в админки (т. е. в файл www\admin\controller\module\имя_модуля.php). Он принимает его и записывает в БД, а точнее в таблицу “префикс_setting“. Где в отведенной строке для вашего модуля будут сохранены настройки в виде “ключа: значения“.

Поподробнее..

В tpl шаблоне админинки модуля (т. е. в файле www\admin\view\template\module\filterattr.tpl) все настройки которые вы вводите, это значения тегов input, select и т. п., которые находятся в форме:

 <form action="<?php echo $action; ?>" method="post" enctype="multipart/form-data" id="form">

При нажатие на «Сохранить», вы просто посылаете POST запрос на <?php echo $action; ?> (адрес контроллера модуля в админке, т. е. на файл www\admin\controller\module\имя_модуля.php) с значениями из формы.

Тем самым контроллер модуля в админке принимает этот запрос с помощью функции editSetting(‘имя_модуля’, $this->request->post) модели setting/setting‘.

Кусок кода в контроллере модуля в админки отвечающий за прием POST запросов выглядит так

$this->load->model('setting/setting');

if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
$this->model_setting_setting->editSetting('имя_модуля', $this->request->post); 

$this->session->data['success'] = $this->language->get('text_success');

$this->redirect($this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL'));
}

Функция «editSetting» принимает параметры из формы и записывает в БД, в таблицу с именем префикс_setting в строку с столбцом group с именем модуля.

Например, для модуля «baner» в phpmyadmin строка с его параметрами будет выглядеть так

module my options example

Параметры хранятся в столбце value данной строки, для модуля banner они следующие:

 

a:1:{
i:0;
a:7:{
    s:9:"banner_id";
    s:1:"6";
    s:5:"width";
    s:3:"200";
    s:6:"height";
    s:3:"182";
    s:9:"layout_id";
    s:1:"3";
    s:8:"position";
    s:11:"column_left";
    s:6:"status";
    s:1:"1";
    s:10:"sort_order";
    s:1:"3";}
}

Здесь приведен список параметров с значениями, хотя выглядит немного не логичным.

Сначала пишется параметр в кавычках, далее в кавычках его значение. Например параметр “width” имеем значение «200». Итак, где хранятся параметры и как они туда попадают разобрались.

Теперь разберемся как модуль их получает при выводе своего шаблона на страницу

В контроллере модуля (не админском контроллере модуля), т.е. в файле «www\catalog\controller\module\имя_файла.php» всегда присутствует функция

 

protected function index() {
...
}

 

Она вызывается когда к модулю происходит запрос, т. е. в любом том случае когда его надо вывести.

Когда нам нужно передать параметры из админки модуля в сам модуль, нам нужно указать в качестве аргумента данной функции переменную «$setting», т.е. должно быть:

protected function index($setting) {
…
}

$setting это массив с ключами, например если вам нужно получить значение параметра “width”, вы обращаетесь к массиву так
$setting['width']

 

Решение по шагам

1. Добавим в админский tpl шаблон (т. е. в файл www\admin\view\template\module\имя_модуля.tpl) нашего модуля в тело формы

<form action=”<?php echo $action; ?>” method=”post” enctype=”multipart/form-data” id=”form”>

следующий тэг:

<td class="left">
<input type="text" name="имямодуля_module[0][param1]" value="123" size="3">
</td>

Где «имямодуля_module[0][param1]» обязательный формат, здесь “param1” – имя параметра.
value – значение параметра по умолчанию (можно оставить пустым)

Что бы не поехала шапка таблицы настроек в админке, можете добавить столбец в первый <tr>

Например такой

<td class="left">Мой параметр</td>

Теперь в админка модуля будет выглядеть так

module my options

Внизу tpl шаблона, есть JavaScript функция function addModule(), добавьте данную <td> в код, это нужно для того что-бы пользователь мог добавить новый модуль на другие страницы (схемы в терминологии OpenCart).

 

2. В админском контроллере модуля (т. е. в файле www\admin\controller\module\имя_модуля.php) нужно обязательно добавить следующий код

$this->load->model('setting/setting');		

if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
	$this->model_setting_setting->editSetting('имя_модуля', $this->request->post);						
	$this->session->data['success'] = $this->language->get('text_success');						
	$this->redirect($this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL'));
}

Он означает что POST запросы для данного модуля нужно обрабатывать и заносить в БД.

Данный код скорее всего уже есть в контроллере вашего модуля, поэтому идем дальше.

 

3. В контролере модуля (т. е. в файле www\catalog\controller\module\имя_модуля.php)

Добавить аргумент $setting в функцию

protected function index() {
...
}

Т.е. должно стать так

protected function index($setting) {
...
}

Далее, в любом месте контроллера добавить

$this->data['param1'] = $setting["param1"];

Это позволит, шаблону tpl данного модуля использовать данный параметр, виден он будет под именем «param1».

 

4. Теперь в tpl шаблоне модуля (т. е. в файле www\catalog\view\theme\default\template\module\filterattr.tpl) мы можем использовать данный параметр как нам нужно, например выведем его значение:

 

<?php echo $param1; ?>

Результат будет:

 

123