Hero

Como crear una regla de contexto vía código en Drupal 7

Abril 02, 2013

enzo
Drupal

Como ya es conocido por casi todos el módulo de Context es un herramienta poderosa para determinar el contenido y estructuras de nuestros nodos en Drupal, pero a pesar de que existen múltiples módulos que permiten cambiar el tema a utilizar o definir que archivos de CSS o JS cargar, esta operación requiere conocimientos intermedio/avanzados de como funciona Drupal y de context, limitando el uso de esto a los programadores y site builders.

Sin embargo en algunas ocasiones los editores del contenido hacen solicitudes que pudieran ser solventadas si tan solo ellos pudieran crear sus propias reglas de contexto, pero a veces eso es pedir demasiado. En estos casos no todo esta perdido porque aun podemos programar un módulo que genere reglas de contexto basado en opciones sencillas provistas por los editores de contenido.

A continuación mostrare un ejemplo de como hacer una regla de contenido usando el módulo Context Add Assets para poder incluir un archivo de CSS arbitrario para cada nodo.

  1. Crear interfaz para el editor de contenido.

Mediante la implementación del hook_form_alter modificaremos el formulario de edición del módulo para permitir seleccionar al usuario el archivo arbitrario de CSS presente en nuestro tema por defecto, como se muestra a continuación.

function hook_form_alter(&$form, &$form_state, $form_id) {


 if ( module_exists('context_addassets') && isset($form['type']) && isset($form['#node']) && $form['type']['#value'] . '_node_form' == $form_id ) {
 $current_theme = variable_get('theme_default', 'none');
 
 $options = _context_addassets_scandir('css', 'themes');

 $options = !$options ? array() : $options;
 $options_array = array();

 foreach ($options as $key => $value) {
 $path = $key;
 $key = explode(' -- ', $value);
 $value = $key[1];
 $key = trim($key[0]);
 $options_array[$key][$path] = $value;
 }

 $form['#tree'] = TRUE;

 $context_name = context_by_node_get_name($form['nid']['#value']);

 if (isset($context_name['name'])) {
 $context_object = context_load($context_name['name']);
 $values = array_keys($context_object->reactions['css'][ucfirst($current_theme)]);
 $default_value = $values[0];
 } else {
 $default_value = '';
 }

 foreach ($options_array as $key => $items) {
 if (strtolower($current_theme) == strtolower($key)) {
 $select_options = array();
 foreach ($items as $path => $file_name) {
 $select_options[$file_name] = basename($file_name);
 }

 $form['css_file'] = array(
 '#type' => 'select',
 '#title' => t('Selected a css file'),
 '#options' => $select_options,
 '#default_value' => $default_value,
 '#description' => t('Set the css file must be loaded with page is redered.'),
 );
 }
 }

 $form['#submit'][] = '_function_css_file_submit';
 }
}

En el código anterior verificamos que sea una edición de un nodo y que el modulo context_addassets este habilitado.

if ( module_exists('context_addassets') && isset($form['type']) && isset($form['#node']) && $form['type']['#value'] . '_node_form' == $form_id ) {

Adicionalmente se le podría agregar una página de configuración donde determinar que tipos de contenido tendrán la posibilidad de escoger el archivo de CSS arbitrario.

Posteriormente se obtiene el tema por defecto y se hace uso de la función _context_addassets_scandir para obtener los archivos de CSS dentro del tema.

 $options = _context_addassets_scandir('css', 'themes');

Posteriormente se crean un elemento de tipo select donde el editor de contenido podar escoger el archivo de CSS deseado, y la salida seria similar a la siguiente imagen.

select box css file

Para finalizar se agrega una función extra de procesamiento llamada _function_css_file_submit como se muestra a continuación.

 $form['#submit'][] = '_function_css_file_submit';

Asumiremos que se define una variable de session $_SESSION[‘css_file’] basándose en la selección del usuario.

  1. Crear regla de contexto vía código.

Haciendo uso del hook_node_insert crearemos una regla de contexto para los nuevos nodos como se puede apreciar a continuación.

/**
 * Implements hook_node_insert().
 */
function hook_node_insert($node) {

 $current_theme = ucfirst(variable_get('theme_default', 'none'));

 if (!context_by_node_exist($node->nid)) {
 // Create the new Context
 $context = new stdClass();
 $context->reactions = array();
 $context->condition_mode = 0;
 $context->hidden = 1;
 $context->name = 'context_by_node_' . $node->nid;
 $context->description = t('Context by Node: @title [@nid]', array('@title' => $node->title, '@nid' => $node->nid));
 $context->tag = 'Context by Node';
 $context->conditions = array(
 'path' => array(
 'values' => drupal_map_assoc(array('node/' . $node->vid)),
 ),
 );

 $context->reactions = array(
 'css' => array(
 $current_theme => array($css_file => $_SESSION['css_file'],
 ),
 );

 context_save($context);
 }
}

El código anterior se limita a crear un objeto que sea enviado a la función context_save del módulo de Context, la regla de contexto anterior utiliza la propiedad conditions para agregar una condición de tipo path para que solo se aplique cuando se este visitando el nodo que se acaba de insertar. En la propiedad reactions se agrega una reacción que sera interpretada por el módulo Context Add Assets.

Es posible agregar otras reacción y la forma mas fácil de hacer es primero crear la reacción utilizando la interfaz de Context y luego exportar la regla para determinar que estructura se debe colocar en la reacción para que pueda ser interpretada correctamente.

  1. Actualizar regla de contexto vía código.

Obviamente que también necesitamos proveer una forma de poder actualizar la regla de contexto, para lo cual haremos una implementación del hook_node_update como se puede apreciar a continuación.

/**
 * Implements hook_node_update().
 */
function hook_node_update($node) {

 $current_theme = ucfirst(variable_get('theme_default', 'none'));

 if($context_object = context_load('context_by_node_' . $node->nid;);

 $context_object->reactions = array(
 'css' => array(
 $current_theme => array($css_file => $_SESSION['css_file'],
 ),
 );

 context_save($context_object);
 }
}

En este caso solo se carga la regla de contexto por medio del nombre usando la función context_load del módulo de Context y se hace la actualización de la reacción.

El proceso de borrado de la regla de contexto se deja para que el lector lo implemente.

Espero que haya sido de su agrado.

enzo

Recibe consejos y oportunidades de trabajo 100% remotas y en dólares de weKnow Inc.