Własna akcja w module Views Bulk Operations
Moduł Views Bulk Operations jest używany, gdy chcemy dodać możliwość wykonywania masowych operacji na wybranych encjach. Mimo wbudowanych akcji takich jak np. publikacja czy usuwanie wpisów, w prosty sposób można dodać własne, złożone akcje. W tym przykładzie pokazane będzie jak dodać akcję, która zmieni stan wpisu (Workflows).
Akcja wykonywana jest na wszystkich zaznaczonych wpisach i z automatu wykonuje się w kolejkach Batch tak, aby nie przeciążyć systemu i nie spowodować “wywalenia” się strony, gdy proces wykonuje się za długo.
Jeżeli wiesz, co robisz i masz ku temu powody, to w konfiguracji pola możesz wyłączyć opcję kolejkowania.
Instalacja i konfiguracja VBO
Moduł Views Bulk Operations instaluje się poprzez ściągnięcie i rozpakowanie paczki w katalogu modules/contrib lub za pomocą komendy composer, która ściągnie najnowszą stabilną wersję modułu.
composer require drupal/views_bulk_operations
Po instalacji modułu nie trzeba w żaden sposób konfigurować, a wystarczy dodać odpowiednie pole do strony (lub bloku) utworzonego przez moduł Views.
- Dodaj nowy widok z treściami (Content), który tworzy stronę.
- Format wyświetlania ustaw na Tabela.
Nie jest to konieczność, po prostu checkboxy na tabeli wyglądają naturalniej - Dodaj pole tytułu
- Dodaj pole Views bulk operations
Konfiguracja akcji dla pola VBO
W konfiguracji pola można zaznaczyć, które masowe akcje będą mogły być wykonywane na wynikach. Jest tam kilkanaście predefiniowanych akcji, takich jak na przykład:
- usuwanie wpisów
- publikowanie
- przyklejanie
Powyższa lista jest zgodna, gdy widok wyświetla zawartość (Content). Jeżeli dodasz widok wyświetlający użytkowników (Users), to zauważysz, że lista ma inne akcje.
Dodanie własnej akcji do VBO
Celem jest dodanie własnych akcji na wpisach (Content), które zmienią stan (Workflows) wybranych wpisów.
Stany wpisów nie są dostępne od razu po instalacji Drupala. W tym celu trzeba włączyć dwa dodatkowe moduły, które znajdują się bezpośrednio w Drupalu. Nie trzeba ściągać nic dodatkowego.
Wejdź na stronę z modułami - admin/modules
Włącz moduły: Workflows i Content moderation
Konfiguracja Workflows
Dla celów tego wpisu wykorzystam automatycznie zdefiniowane stany dla typu Editorial, który dostępny jest od razu po włączeniu modułu Content moderation.
Jedynie co trzeba zrobić, to włączyć dany typ przejścia stanów dla wybranych rodzajów zawartości.
- Na stronie admin/config/workflow/workflows edytuj typ Editorial
- Ustaw typ zawartości Artykuł (Article)
Ta operacja doda nowe pole do każdego formularza dodawania/edycji artykułu.
Do widoku gdzie jest pole VBO dodaj:
- pole wyświetlające stan danego wpisu - Content: Moderation state
- filtr, który ograniczy wyświetlanie wpisów z typu Artykuł
Jeżeli dodany jest filtr ograniczający wpisy jedynie do tych opublikowanych Content: Published (= Yes), to go usuń. Będzie blokował wyświetlanie wpisów, które mają stan np. Draft lub Archived, które z definicji są niepublikowane.
Kod własnej akcji
Stwórz własny moduł i włącz go. W moim przypadku moduł nazywa się d_workflows
W katalogu modułu stwórz strukturę katalogów src/Plugin/Action
Utwórz w nim nowy plik z klasą dla akcji zmiany stanu wpisu na Published.
Nazwa pliku: PublishNodeAction.php
/**
* Content moderation publish node.
*
* @Action(
* id = "d_workflows_publish_node_action",
* label = @Translation("Publish node (moderation_state)"),
* type = "node",
* confirm = TRUE
* )
*/
class PublishNodeAction extends ViewsBulkOperationsActionBase {
Ważna jest tutaj adnotacja klasy.
Ustalasz w niej id dla akcji, może być to dowolna unikalna wartość. Warto w jej nazwie zawrzeć nazwę modułu oraz to, co dana akcja robi.
Label to wartość, która pojawi się w konfiguracji pola VBO.
Type to typ encji, dla której będzie dostępna nowa akcja. W tym przypadku jest to node, ale może być na przykład user, taxonomy_term czy jakakolwiek inna.
Nasza klasa dziedziczy po ViewsBulkOperationsActionBase
Wymaga to zadeklarowania dwóch metod:
- execute() - co ma zostać wykonane dla każdego rekordu
- access() - kto może wykonać akcję
Przykładowy kod metody execute()
/**
* {@inheritdoc}
*/
public function execute(ContentEntityInterface $entity = NULL) {
if (!$state = $entity->get('moderation_state')->getString()) {
return $this->t(':title - can\'t change state',
[
':title' => $entity->getTitle(),
]
);
}
switch ($state) {
case 'archived':
case 'draft':
$entity->set('moderation_state', 'published');
$entity->save();
break;
}
return $this->t(':title state changed to :state',
[
':title' => $entity->getTitle(),
':state' => $entity->get('moderation_state')->getString(),
]
);
}
Pierwszy warunek sprawdza, czy dana encja ma włączoną opcję ustalania stanów.
W naszym przypadku jest to jedynie Article. Gdy akcja będzie zainicjowana na wpisach bez włączonych stanów (puste $entity->get('moderation_state')->getString()), to zostanie przerwana i informacja o tym zostanie wyświetlona.
Warunek można łatwo rozszerzyć o np. sprawdzanie rodzaju zawartości dla encji.
$entity->bundle()
W dalszej części kodu sprawdzany jest aktualny stan wpisu i jeżeli warunek jest spełniony, to kod zmienia stan na Published.
$entity->set('moderation_state', 'published');
Przykładowy kod metody access()
/**
* {@inheritdoc}
*/
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
if ($object instanceof Node) {
$can_update = $object->access('update', $account, TRUE);
$can_edit = $object->access('edit', $account, TRUE);
return $can_edit->andIf($can_update)->isAllowed();
}
return FALSE;
}
W tym prostym warunku sprawdzane jest, czy operujemy na obiektach typu Node oraz czy użytkownik wykonujący akcję ma do niego uprawnienia edycji i update. W przeciwnym wypadku kod zwróci FALSE i akcja nie zostanie wykonana.
Cały plik PublishNodeAction.php wygląda tak:
<?php
namespace Drupal\d_workflows\Plugin\Action;
use Drupal\node\Entity\Node;
use Drupal\views_bulk_operations\Action\ViewsBulkOperationsActionBase;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Entity\ContentEntityInterface;
/**
* Content moderation publish node.
*
* @Action(
* id = "d_workflows_publish_node_action",
* label = @Translation("Publish node (moderation_state)"),
* type = "node",
* confirm = TRUE
* )
*/
class PublishNodeAction extends ViewsBulkOperationsActionBase {
use StringTranslationTrait;
/**
* {@inheritdoc}
*/
public function execute(ContentEntityInterface $entity = NULL) {
if (!$state = $entity->get('moderation_state')->getString()) {
return $this->t(':title - can\'t change state',
[
':title' => $entity->getTitle(),
]
);
}
switch ($state) {
case 'archived':
case 'draft':
$entity->set('moderation_state', 'published');
$entity->save();
break;
}
return $this->t(':title state changed to :state',
[
':title' => $entity->getTitle(),
':state' => $entity->get('moderation_state')->getString(),
]
);
}
/**
* {@inheritdoc}
*/
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
if ($object instanceof Node) {
$can_update = $object->access('update', $account, TRUE);
$can_edit = $object->access('edit', $account, TRUE);
return $can_edit->andIf($can_update)->isAllowed();
}
return FALSE;
}
}
W edycji pola VBO będzie dostępna nowa akcja.
Podsumowanie
Doświadczeni programiści Drupala jak również konsultanci Drupala zapewniają, że dodanie nowych akcji do Views Bulk Operations jest proste i sprowadza się do stworzenia dodatkowej klasy z dwoma metodami. Na podstawie tego prostego przykładu możesz budować bardziej złożone akcje masowe na encjach różnego typu.