Контрол над темата - Част 1

Постепенно стигнахме до много интересната част - създаване на интерфейс, с помощта на който потребителят ще има възможност да променя визуалните елементи на темата. Това трябва да стане разбира се в рамките и с инструментите, които ни предоставя Drupal. За целта ще добавим контролни елементи към формата за контрол на поведението на темата. Можем да я достигнем като в главното меню изберем Appearance и в дясно от иконата на нашата тема изберем "Settings". В нашия случай това ще ни отведе до адрес http://localhost/drupal_8/admin/appearance/settings/deep_theme. Можем да се уверим, че това е форма, съдържаща стандартните контроли от Drupal 8 и да запретнем ръкави и да поровим под капака на Drupal.

Добавянето на допълнителни контроли към тази форма изисква познания по промяната (alter) на форми в Drupal. И понеже това е по-скоро нещо, което е присъщо за backend-девелопмента ще разяснявам нещата в движение. Като за начало трябва да се знае, че формите в Drupal се дефинират с помощта на функции, които връщат масиви с описание на елементите на формата. В самата система съществува т.нар. Form Api, което съдържа всички елементи, които могат да се добавят в една форма. Можем да видим визуално описание на тези елементи на адрес:

https://api.drupal.org/api/drupal/developer%21topics%21forms_api_reference.html/7.x

В областта на backend-девелопмента познаването му е от ключово значение, но за хора, които тепърва навлизат в програмирането на Drupal е възможно да се запознаят само с няколко компонента, които са необходими за работа с потребителските настройки за управление на темата. Нека да разгледаме как се дефинира форма в html:

<form>
  <label for="sevice-1-title">Service 1</label>
  <input type="text" name="sevice-1-title" id="sevice-1-title" />
<form>

Умишлено съм пропуснал атрибутите action и method на form-таг-а, както и бутона submit, защото искам да се концентрираме върху съдържанието на формата, в случая това са етикет и поле за въвеждане. Ако искаме същото поле да включим в Drupal форма, то трябва да дефинираме функция, която да върне масив с описание на всички елементи на формата. Те от своя страна също са описани като масиви. Кодът, който трябва да въведем за едно текстово поле е:

$form['service_1_title'] = array(
  '#type' => 'textfield',
  '#title' => t('Service 1 title'),
  '#description' => t('Type the title for the first service'), 
  '#default_value' => theme_get_setting('service_1_title'),
);

За хората, които се занимават с PHP това си е стандартен асоциативен масив, обяснение изисква неговото съдържание.

$form['service_1_title'] = array() - На първо място е името на целия масив - service_1_title. Това име е особено важно, защото по него ще бъде достъпвана стойността на полето.

 '#type' => 'textfield', - описание на самото поле - тип (в случая това е input поле за въвеждане на текстов низ). Ако не сте посетили линка към Form API Ви приканвам да го направите сега, като обърнете внимание на типа textfield

 '#title' => t('Service 1 title'), - Заглавие на полето. При визуализиране на елемента това ще е етикета на полето (<label>)

'#description' => t('Type the title for the first service'), - Допълнително пояснение за улеснение на потребителя.

 '#default_value' => theme_get_setting('service_1_title'), - това поле изисква малко повече обяснение. Ключът '#default_value' определя стойността, която ще бъде заредена по подразбиране в поето при зареждане на формата. При пъвоначално зареждане то ще е празно, но ако да речем при натискане на бутона Submit полето е съдържало "Маникюр", то при последващо зареждане на формата то отново ще съдържа думата маникюр, защото тя ще бъде асоциирана като съдържание на полето с име service_1_title

Нека сега разгледаме какво принципно се случва при натискане на бутона Submit в която и да е форма. Техниката, която се употребява тук е стандартна за всички форми в Drupal. Нека си представим поведението на формата. След като потребителят въведе стойност и натисне бутона Submit таи стойност се изпраща за обработка. В PHP това е определен скрипт, който взима стойността и извършва опредени действия. В Drupal при натискането на бутона се изпълнява определена функция. Нещата са строго дефинирани и доста елегантни. Обикновено последователността е следната:

1. Дефинира се функция, връщаща масив с описание на елементите на формата. Нека да й дадем примерно името deep_theme_form.

2. Дефинира се функция, отговаряща за изпълнение на код при натискане на бутон submit. Ако искаме да не я описваме дефинативно можем просто да я наречем с името deep_theme_form_submit. Добавqнето на submit към името гарантира, че тази функция ще бъде изпълнена при натискане на бутон Submit. Има възможност за дефиниране и на други функции при натискане на submit с произволно име, но засега оставяме нещата така.

3. Нека си представим следната ситуация: Някъде някой е създал форма, която обаче искаме да променим или просто да добавим нови елементи към нея. За целта не трябва да търсим къде тази форма е описана, за да променим кода в нея, а просто да създаден функция с име създадено по определени правила. Ако искаме да го направим в тема, името на функцията започва с името на темата. Ако го правим в модул, трябва да започва с името на модула. Следва името на формата и накрая завършва с добавката _alter . Това е важна техника широко използвана в Drupal. Нека го разясним с пример. Приемаме, че някъде в сайта имаме функция дефинираща форма с ID = "some_form". Ако искаме да допълним формата, дефинирана в some_form с други контроли в нашата тема трябва да създадем функция с име deep_theme_some_form_alter(). И ако на теория всичко това звучи объркващо с практиката, която ще изпълним сега мисля, че нещата ще ни се изяснят.

Задачата която имаме е да допълним аминистративната форма с опции на нашата тема deep_theme с полета, с помощта на които ще можем да променим заглавията на услугите в темата.

Тук искам да направя уточнението, че дефинирането на подобна триколонна част от началната страница на сайта е добре да се изведе в отделен блок, а не да е дефинирано в самата тема. Това обаче изисква познания по програмиране на модули, което не е цел на настоящото ръководство. Показваните техники имат за задача по-скоро да ни научат как се добавят потребителски опции в темата.

За да направим това трябва в основната директория на темата да създадем нов файл с име съдържащо името на темата и разширение theme. В нашия случай това е deep_theme.theme. Това е специален файл в който се дефинират хуковете на темата. Иначе съдържанието му е на обикновен php файл, следователно трябва да започва с <?php

Ако не знаете какво е hook задължително трябва да се запознаете с това понятие, понеже то е широко използвано както в Drupal, така и в WordPress. Най-общо казано това са функции, които се изпълняват при настъпване на определено събитие. Точно кога и как се изпълнява даден hook зависи от съответната CMS. В Drupal това става чрез точно дефиниране на името на функцията, затова ако даден hook не се изпълни много внимателно проверете дали името отговаря точно.

Вътре в тялото на файла дефинираме функция с име

deep_theme_form_system_theme_settings_alter

Нека обърнем повече внимание на името на този hook. Започва с името на нашата тема deep_theme, продължава с името на hook-а, дефиниран в ядрото на Drupal за описание на формата с опции на темата - hook_form_system_theme_settings (като hook е заменено с името на темата) и завършва с _alter, което означава, че нашата функция ще се изпълни заедно с изпълнението на основния hook и ще допълни масива, съдържащ формата с нов масив който ще дефинира нови елементи на формата:

<?php

/* 
 * Implements hook_form_system_theme_settings
 */
function deep_theme_form_system_theme_settings_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
  $form['left_service_title'] = array(
    '#type' => 'textfield',
    '#title' => t('Left Service Title'),
    '#description' => 'The service title will be vissible on the left service section on the frontpage',
    '#default_value' => theme_get_setting('left_service_title'),
  );
  
  $form['middle_service_title'] = array(
    '#type' => 'textfield',
    '#title' => t('Middle Service Title'),
    '#description' => 'The service title will be vissible on the middle service section on the frontpage',
    '#default_value' => theme_get_setting('middle_service_title'),
  );
  
  $form['right_service_title'] = array(
    '#type' => 'textfield',
    '#title' => t('Right Service Title'),
    '#description' => 'The service title will be vissible on the right service section on the frontpage',
    '#default_value' => theme_get_setting('right_service_title'),
  );
}

Обръщам внимание, че функцията не връща никаква стойност, защото променливата, която се допълва с масивите на елементите - $form е подадена по референция. Като резултат след записа на файла и изчистване на кеш-а достъпвайки формата за настройка на deep_theme трябва да изглежда така:

theme settings

Като завършек искам да кажа, че интерфейса може да се обогати много и ние ще го направим, но като начало е много важно да работим с форми в Drupal, затова трябват малко повече усилия и постоянство, за да се създаде рутина. Разучаването на Form API е от ключово значение. По-нататък ще добавим елементи за качване на потребителски снимки, цели полета с параграфи и т.н. Засега ще се ограничим с имената на услугите на сайта, като в следващата статия ще изведем съдържанието на полетата на началната страница.