Drupal 8 permite usar todo su entorno de plantillas, menús, bloques y permisos para nutrir de html renderizado a otros frameworks como Magento, WordPress, etc.
Uno de los “mantras” que tenemos en Biko a la hora de ofrecer Drupal a nuestros clientes es que no solo se trata de un simple gestor de contenidos, sino de un completo entorno de desarrollo: un señor framework con el que puedes construir tu traje a medida.
Que conste que no es una frase hecha. Drupal 8 permite usar todo su entorno de desarrollo, con sus plantillas, menús, bloques, regiones, módulos, permisos, etc. para nutrir de datos a otros frameworks. Es decir, podemos usar Drupal para gestionar, por ejemplo, los contenidos de Magento, aplicaciones Symfony a medida, etc.
Drupal gestionando un Magento
Vamos a ver un caso concreto. En estos momentos estamos desarrollando, en colaboración con KPMG y ADN, toda la estrategia de omnicanalidad para uno de nuestros clientes, una importante y conocida empresa de restauración en expansión internacional. Uno de los requisitos del proyecto es usar Magento Enterprise Edition para la parte de e-commerce y fidelización de clientes. Sin embargo, y aquí viene el quid de la cuestión, el cliente no quiere usar Magento para la gestión diaria, ¡sino Drupal 8! ¡Bien!
La idea es usar toda la potencia de edición de Drupal para gestionar los textos, imágenes y maquetación de los productos que se venderán a través de Magento, ya que Magento cojea un poco en estos aspectos. Además, el cliente no quiere que su equipo de marketing tenga que lidiar con Magento, sino con Drupal, un entorno con el que ya están familiarizados.
¿Y cómo lo hacemos?
Necesitamos enviarle a Magento dos elementos ya renderizados, para que los integre con su sistema de plantillas:
- Menú superior: cuando se añade un nuevo enlace o se modifica el orden de sus elementos, enviamos el HTML a Magento
- Bloque content de la ficha de producto: cuando se actualiza cualquier dato del producto, enviamos el HTML a Magento
NOTA: insisto en que necesitamos enviarlos ya renderizados, como una simple cadena HTML. No nos sirve la REST API de Drupal 8 para exponer datos a Magento, ya que queremos que Drupal controle completamente el proceso de renderizado.
Vamos a ver los pasos que hemos dado para construir esta integración:
1.Cambio de theme activo al vuelo
El primer paso es conseguir cambiar de theme al vuelo. La razón es que, cuando el menú o el producto se modifican y capturamos su HTML, estamos actuando sobre el admin de Drupal, cuyo theme suele ser Seven. Así que el renderizado que conseguimos usa, cómo no, Seven, y no el theme que hayamos definido para nuestro frontend.
Nos remangamos y vamos a cambiar el theme activo al vuelo.
Primero tenemos que saber el nombre de nuestro theme de admin (normalmente será “seven”, en minúsculas). Utilizamos el servicio “theme.manager” (\Drupal::theme() nos da acceso directo a este servicio). Lo guardaremos para volver a activar este theme cuando hayamos terminado:
$adminThemeName = \Drupal::theme()->getActiveTheme()->getName();
Ahora obtenemos el nombre del theme que estamos usando para el frontend. Usamos la clave de configuración “system.theme” para el theme por defecto:
$frontendThemeName = \Drupal::config('system.theme')->get('default');
En ambos casos obtenemos un string, que usaremos a continuación para activar el theme que queremos. Para ello, nos servimos del servicio theme.initialization para iniciar nuestro theme de frontend:
$themeInitializationService = \Drupal::service('theme.initialization');
$frontendTheme = $themeInitializationService->initTheme($frontendThemeName);
Reseteamos el theme activo en este momento (si no no podemos activar uno nuevo) y activamos nuestro theme de frontend:
\Drupal::theme()->resetActiveTheme();
\Drupal::theme()->setActiveTheme($frontendTheme);
2. Renderizado del menú superior
Capturamos el momento de la edición del menú con el hook hook_entity_update (como es un menú, “mymodule_menu_update”). Lo importante en este paso es identificar el menú que nos interesa (en nuestro caso “main”) y luego obtener su block, que tendrá un key distinto a “main” (en nuestro caso, “frontend_main_menu”).
Omito varias partes del código por claridad y centrarme solamente en el renderizado del menú:
function mymodule_menu_update(Drupal\Core\Entity\EntityInterface $entity) {
if ($entity->id() == 'main') {
// Cambiamos el theme activo al vuelo (el código del paso anterior)
// …
// Obtenemos el bloque del menú
$blockEntity = \Drupal\block\Entity\Block::load('frontend_main_menu');
// Obtenemos el render array del bloque
$blockRenderArray = \Drupal::entityTypeManager()->getViewBuilder('block')->view($blockEntity);
// Renderizamos el bloque del menú
$blockHtml = \Drupal::service('renderer')->render($blockRenderArray);
// Enviamos $blockHtml a Magento, mediante SOAP u otro método
// Veremos un ejemplo al final
// ...
// Restituimos el theme original (el código del paso anterior)
// ...
}
}
3. Renderizado de la ficha del producto
Capturamos el momento de la edición del producto con el hook hook_entity_update (como es un node, “mymodule_node_update”). Lo importante en este paso es definir el view mode que queramos (full, teaser, etc). En nuestro caso, “full”.
Omito varias partes del código por claridad y centrarme solamente en el renderizado del producto:
function mymodule_node_update(Drupal\Core\Entity\EntityInterface $entity) {
// Cambiamos el theme activo al vuelo (el código del primer paso)
// …
// Obtenemos el render array del producto
$renderController = \Drupal::entityTypeManager()->getViewBuilder($entity->getEntityTypeId());
$nodeRenderArray = $renderController->view($entity, 'full');
// Renderizamos el html del producto
$nodeHtml = \Drupal::service('renderer')->render($nodeRenderArray);
// Enviamos $nodeHtml a Magento, mediante SOAP u otro método
// Veremos un ejemplo al final
// ...
// Restituimos el theme original (el código del primer paso)
// ...
}
En cuanto al envío de datos a Magento, podemos usar su API SOAP de una forma muy sencilla:
$client = new SoapClient('http://example.com/mage1/api/soap/?wsdl');
$sessionId = $client->login('USER', 'PASSWORD');
$result = $client->call($sessionId, 'catalog_product.update', array($sku, array(
'productHtml' => $nodeHtml
)));
¡Listo! Ya podemos usar Drupal para controlar Magento, WordPress o lo que queramos. Vaya, me viene a la mente la frase “uno para gobernarlos a todos” del Señor de los Anillos, ¡je!