Введение

Многие задаются вопросом, как добавить дополнительные поля в стандартный компонент com_content CMS Joomla 2.5, не устанавливая громоздких расширений, ради этого. В этой статье мы разработаем плагин, который будет демонстрировать как легко добавить любые дополнительные поля в статью компонента com_content, не изменяя файлы ядра, что позволит без страха утери изменений обновлять CMS до актуальной версии.

Для разработки данного расширения вы должны иметь, хотя бы, основные навыки разработки шаблонов для данной CMS и хорошее знание языка PHP.

В ходе разработки мы сделаем следующее:

  1. Добавим дополнительные поля к форме редактирования статьи в административной части.
  2. Добавим дополнительные поля к форме редактирования статьи с лицевой части сайта.
  3. Сохраним значения полей в базу данных.
  4. Выведем значения полей в таблице при отображении статьи.

Результат работы

Этот пример добавит три свойства еды в статью. Свойства будут состоять из: формы, температуры и вкуса. Если данные свойства заполнены, то они будут отображаться в виде простой таблицы перед содержанием статьи.

Вывод результата в виде таблицы перед основным содержанием статьи:

Результат работы плагина

Доступ к редактированию дополнительных полей с front-end:

Редактирование дополнительных полей с front-end

Редактирование дополнительных полей с back-end:

Редактирование дополнительных полей с back-end

Фреймворк

В Joomla, статьи редактируются в базовой форме, обрабатываемые компонентом. Обработка формф в административной части аналогична, обработки формы с лицевой части сайта. При работе с формой выполняются следующие действия:

  1. Загружается основное описание формы в виде XML структуры.
  2. Загружает пользовательские данные, если они существуют в базе данных.
  3. Внедряет данные в форму.
  4. Рендерит и отображает форму для следующей обработки пользователем.
Когда пользователь закончил обработку формы и нажал кнопку «Сохранить», произойдет:

  1. Захватывает предоставленные данные.
  2. Загружает форму описания.
  3. Сверяет полученные данные с формой описания.
  4. Если проверка не пройдена, то сохраняет данные в форме и начинает с самого начала.
  5. Обновляет необходимые поля в базе данных.
Фреймворк имеет события для всех этих программных моментов. В этом примере плагин будет подключать события для расширения функционала формы.

Список используемых событий:

onContentPrepareForm() - вызывается после загрузки основной формы описания. Данное событие поможет добавить новую группу дополнительных полей в материал.

onContentPrepareData() - вызывается после загрузки статьи из базы данных в форму редактирования. Событие поможет добавить сохраненные значения дополнительных полей в форму редактирования.

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

onContentAfterDelete() - вызывается после удаления статьи. Позволит удалять значения дополнительных полей из базы данных.

onContentPrepare() - событие вызывается перед тем как статья будет отображена. Позволит вставить значения дополнительных полей в таблицу перед текстом статьи.

База данных

Содержимое дополнительных полей должно хранится в базе данных. В идеале содержимое должно храниться в отдельной таблице. Однако это потребует создания дополнительной таблицы. В Joomla 2.5 возможно расширить пользовательские данные. Дополнительные поля хранятся в таблице #__user_profiles. Эта таблица построена и используется таким образом, что в ней можно хранить любую необходимую информацию.

Наш плагин будет использовать таблицу #__user_profiles для хранения значений дополнительных полей. В свою очередь эта таблица будет использовать поля user_id как article_id.

Дерево файлов расширения

Созданное расширение будет храниться в каталоге "rating" и будет иметь следующую структуру файлов на сайте:

── plugins/content/rating
   ├── language
   │   └── en-GB
   │       ├── en-GB.plg_content_rating.ini      [Языковой файл]
   │       └── en-GB.plg_content_rating.sys.ini  [Языковой файл]
   ├── rating
   │   ├── rating.css  [CSS для отображения таблицы]
   │   └── rating.xml  [Описание формы]
   ├── rating.php   [Плагин с событиями]
   └── rating.xml   [Манифест]


Манифест

Конфигурационный файл необходимый для установки плагина. Содержит в себе описание плагина, список подключаемых файлов и некоторые конфигурационные поля.

<!--?xml version="1.0" encoding="utf-8"?-->
 <extension version="2.5" type="plugin" group="content" method="upgrade">
  <name>plg_content_rating</name>
  <author>Joomla! Project</author>
  <creationdate>June 2012</creationdate>
  <copyright>(C) 2005 - 2012 Open Source Matters. All rights reserved.</copyright>
  <license>GNU General Public License version 2 or later; see LICENSE.txt</license>
  <authoremail>admin@joomla.org<;/authoremail>
  <authorurl>www.joomla.org</authorurl>
  <version>2.5.0</version>
  <description>PLG_CONTENT_RATING_XML_DESCRIPTION</description>
 
  <files>
   <folder>language</folder>
   <folder>rating</folder>
   <filename plugin="rating">rating.php</filename>
   <filename>index.html</filename>
  </files>
 
  <config>
   <fields name="params">
    <fieldset name="basic">
     <field name="ratingclass_sfx" type="text" label="PLG_CONTENT_RATING_ITEM_FIELD_RATING_CLASS_LABEL" description="PLG_CONTENT_RATING_ITEM_FIELD_RATING_CLASS_DESC"></field>
    </fieldset>
   </fields>
  </config>
 </extension>


Языковые файлы

Языковые файлы должны содержать следующие языковые константы и их значения:

PLG_CONTENT_RATING="Content - Rating"
PLG_CONTENT_RATING_XML_DESCRIPTION="[plg_content_rating] Example plugin on how to add custom fields (texture/temperature/taste) to articles (com_content). Adds ratings to an article, and display them as a table before the article content."
PLG_CONTENT_RATING_SLIDER_LABEL="Rating Options"
PLG_CONTENT_RATING_FIELD_TEXTURE_LABEL="Texture"
PLG_CONTENT_RATING_FIELD_TEXTURE_DESC="What does the sample feel like"
PLG_CONTENT_RATING_FIELD_TEMPERATURE_LABEL="Temperature"
PLG_CONTENT_RATING_FIELD_TEMPERATURE_DESC="What is the temperature of the sample"
PLG_CONTENT_RATING_FIELD_TASTE_LABEL="Taste"
PLG_CONTENT_RATING_FIELD_TASTE_DESC="How does the sample taste"
PLG_CONTENT_RATING_ITEM_FIELD_RATING_CLASS_LABEL="Rating Class"


Русифицировать плагин вы можете сами с помощью любого онлайн переводчика.

CSS

Содержимое CSS файлы для обработки отображения таблицы с значениями дополнительных полей.

div.rating {
 display: block;
 float: left;
 padding-right: 10px;
}
 
div.rating table tr td {
 margin: 1px !important;
 padding: 2px !important;
}
 
div.rating table tr.row0  {
 background-color:#efefef;
}
 
div.rating table tr.row1 {
 background-color:#fff;
}


Описание формы

Описание формы, содержащей дополнительные поля.

 <!--?xml version="1.0" encoding="utf-8"?-->
<form>
 <fields name="rating">
  <fieldset name="rating" label="PLG_CONTENT_RATING_SLIDER_LABEL">
   <field name="texture" type="text" id="texture" description="PLG_CONTENT_RATING_FIELD_TEXTURE_DESC" label="PLG_CONTENT_RATING_FIELD_TEXTURE_LABEL" message="PLG_CONTENT_RATING_FIELD_TEXTURE_MESSAGE" size="30"></field>
   <field name="temperature" type="text" id="temperature" description="PLG_CONTENT_RATING_FIELD_TEMPERATURE_DESC" label="PLG_CONTENT_RATING_FIELD_TEMPERATURE_LABEL" message="PLG_CONTENT_RATING_FIELD_TEMPERATURE_MESSAGE" size="30"></field>
   <field name="taste" type="text" id="taste" description="PLG_CONTENT_RATING_FIELD_TASTE_DESC" label="PLG_CONTENT_RATING_FIELD_TASTE_LABEL" message="PLG_CONTENT_RATING_FIELD_TASTE_MESSAGE" size="30"></field>
  </fieldset>
 </fields>
</form>

События плагина

Главный файл плагина "rating.php" содержит события которые будут вызываться фреймворком Joomla.

Используемые в событиях переменные:

  • $context - строка определяющая вызов.
  • $data - параметром является объект, содержащий значения формы.
  • $article - параметра объекта (JTableContent), представляющий материал.

__construct

Загружает языковые файлы.

public function __construct(& $subject, $config)
{
 parent::__construct($subject, $config);
 $this->loadLanguage();
}

 


onContentPrepareForm


Позволяет расширить форму редактирования материала в обоих интерфейсах (front-end и back-end). Событие загружает фрагмент формы как описано в "rating/rating.xml" и объединяет его с основной формой материала.

public public function onContentPrepareForm($form, $data)
{
 if (!($form instanceof JForm))
 {
  $this->_subject->setError('JERROR_NOT_A_FORM');
  return false;
 }
 
 // Добавление дополнительных полей к .
 JForm::addFormPath(dirname(__FILE__) . '/rating');
 $form->loadFile('rating', false);
 return true;
}


onContentPrepareData

onContentPrepareData() выполняется после загрузки материала из таблицы #__content. Событие будет собирать и устанавливать значения пользовательских полей, которые расположены в таблице #__user_profiles.

Парамерт articleId объекта $data содержит уникальный идентификатор материала. Это число будет использоваться для получения значений дополнительных полей. Если совпадений найдено не будет, то будет создана новая запись, в которой значения по умолчанию будут взяты из описания формы XML.


Важно, что когда onContentPrepareData() возвращает результат, объект $data содержит значения пользовательских полей. Это связано с тем, что Joomla использует их в качестве заполнителей полей. Если пользователь сохраняет новый материал и не заполнил некоторые обязательные поля, то данные значения установятся по умолчанию в дополнительных полях и не пропадут.

public function onContentPrepareData($context, $data)
{
 if (is_object($data)){
  $articleId = isset($data->id) ? $data->id : 0;
  if ($articleId > 0){
 
   // Загружает данные из базы данных
   $db = JFactory::getDbo();
   $query = $db->getQuery(true);
   $query->select('profile_key, profile_value');
   $query->from('#__user_profiles');
   $query->where('user_id = ' . $db->Quote($articleId));
   $query->where('profile_key LIKE ' . $db->Quote('rating.%'));
   $query->order('ordering');
   $db->setQuery($query);
   $results = $db->loadRowList();
 
   // Проверка на ошибки в базе данных
   if ($db->getErrorNum()){
    $this->_subject->setError($db->getErrorMsg());
    return false;
   }
 
   // Слияние данных
   $data->rating = array();
 
   foreach ($results as $v)
   {
    $k = str_replace('rating.', '', $v[0]);
    $data->rating[$k] = json_decode($v[1], true);
    if ($data->rating[$k] === null){
     $data->rating[$k] = $v[1];
    }
   }
  }
  else {
 
   // Загрузка формы
   JForm::addFormPath(dirname(__FILE__) . '/rating');
   $form = new JForm('com_content.article');
   $form->loadFile('rating', false);
 
   // Устнаовка значений по умолчанию
   $data->rating = array();
   foreach ($form->getFieldset('rating') as $field) {
    $data->rating[] = array($field->fieldname, $field->value);
   }
  }
 }
 
 return true;
}


onContentAfterSave

onContentAfterSave()   вызывается после сохранения материала в базе данных в таблицу #__content. Событие будет извлекат значения пользовательских полей из формы и сохранять их в отдельную таблицу.


public function onContentAfterSave($context, &$article, $isNew)
{
 $articleId = $article->id;
 if ($articleId && isset($article->rating) && (count($article->rating))){
  try
  {
   $db = JFactory::getDbo();
 
   $query = $db->getQuery(true);
   $query->delete('#__user_profiles');
   $query->where('user_id = ' . $db->Quote($articleId));
   $query->where('profile_key LIKE ' . $db->Quote('rating.%'));
   $db->setQuery($query);
   if (!$db->query()) {
    throw new Exception($db->getErrorMsg());
   }
 
   $query->clear();
   $query->insert('#__user_profiles');
   $order = 1;
   foreach ($article->rating as $k => $v)
   {
    $query->values($articleId.', '.$db->quote('rating.'.$k).', '.$db->quote(json_encode($v)).', '.$order++);
   }
   $db->setQuery($query);
 
   if (!$db->query()){
    throw new Exception($db->getErrorMsg());
   }
  }
  catch (JException $e)
  {
   $this->_subject->setError($e->getMessage());
   return false;
  }
 }
 
 return true;
}


onContentAfterDelete

onContentAfterDelete() вызывается после удаления материала из базы данных. Событие удалит связанные с материалом значения дополнительных полей.

public function onContentAfterDelete($context, $article)
{
 $articleId = $article->id;
 if ($articleId){
  try
  {
   $db = JFactory::getDbo();
 
   $query = $db->getQuery(true);
   $query->delete();
   $query->from('#__user_profiles');
   $query->where('user_id = ' . $db->Quote($articleId));
   $query->where('profile_key LIKE ' . $db->Quote('rating.%'));
   $db->setQuery($query);
 
   if (!$db->query()){
    throw new Exception($db->getErrorMsg());
   }
  }
  catch (JException $e)
  {
   $this->_subject->setError($e->getMessage());
   return false;
  }
 }
 
 return true;
}

 


onContentPrepare

onContentPrepare() вызывается когда материал подготавливается к отображению. В этот момент в HTML будет добавлена таблица с значениями дополнительных полей. Переменная $params содержит параметры материала, $this->params вызов параметров плагина, как описано в манифесте плагина.

public function onContentPrepare($context, &$article, &$params, $page = 0)
{
 if (!isset($article->rating) || !count($article->rating))
  return;
 
 // Добавляет CSS для отображения значений
 $doc = JFactory::getDocument();
 $doc->addStyleSheet(JURI::base(true).'/plugins/content/rating/rating/rating.css');
 
 // Создание таблицы результатов на лету
 jimport('joomla.html.grid');
 $table = new JGrid();
 
 // Создание колонок
 $table->addColumn('attr')
       ->addColumn('value');  
 
 // заполняем
 $rownr = 0;
 foreach ($article->rating as $attr => $value) {
  $table->addRow(array('class' => 'row'.($rownr % 2)));
  $table->setRowCell('attr', $attr);
  $table->setRowCell('value', $value);
  $rownr++;
 }
 
 // Оборачиваем таблицу блоком <div> с заданным классом
 $suffix = $this->params->get('ratingclass_sfx', 'rating');
 $html = '<div class=".$suffix.">'.(string)$table.'</div>';
 
 $article->text = $html.$article->text;
}
</div>

 


Внимание

Для работы данного плагина требуется CMS не ниже Joomla 2.5.6, для предыдущих версий некоторые события работать не будут.


На саму Joomla необходимо установить патч, добавляющий два события.

Этот патч известен как Joomla патч #28771.

Файлы

Вы можете задать любые вопросы в комментариях к статье.