Skip to content

Instantly share code, notes, and snippets.

@dvessel
Created February 5, 2011 22:37
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dvessel/812873 to your computer and use it in GitHub Desktop.
Save dvessel/812873 to your computer and use it in GitHub Desktop.
drupal_render + CSS simple selectors
<?php
/**
* @file
* Functions related to Drupal 7 render arrays.
*/
/**
* Prints out a Drupal render array filtered by a simple selection.
*
* ren(): Possible uses:
*
* same as the core render() function: - no performance penalty.
* <?php ren($page['content']); ?>
*
* simple selector: - slightly slower, use example above for shallow elements.
* <?php ren($page, 'content'); ?>
*
* descendent selector: - node comment form inside the content region.
* <?php ren($page, 'content nodes comment_form'); ?>
*
* simple selector deep in the tree: - comment_form wherever it is.
* <?php ren($page, 'comment_form'); ?>
*
* if the above was done with core's render() it would look similar to this:
* <?php print render($page['content']['system_main']['nodes'][nid]['comments']['comment_form']); ?>
*
* comma separated groups: - output each element in a specific order.
* <?php ren($content, 'links, body, comment_form, comments'); ?>
*
* @see http://api.drupal.org/api/search/7/render
*
* @param $elements
* The raw drupal render array.
* @param $select
* This works similar in concept to selecting a single id or id's grouped into
* a descendent selector in CSS.
*/
function ren(&$elements, $select = '') {
print implode("\n", ns_elements($elements, $select, 'render'));
}
/**
* Forms a reference to an inner element based on the select string then
* applies a callback function.
*
* @param $elements
* The raw drupal render array.
* @param $select
* This works similar in concept to selecting a single id or id's grouped into
* a descendent selector in CSS.
* @param $callback
* The function callback. Known callbacks: 'render', 'show' or 'hide'.
*/
function ns_elements(&$elements, $select = '', $callback) {
if (!$select) {
return array($callback($elements));
}
$output = array();
foreach (ns_search_keys($select) as $search_keys) {
if ($inner_elements = &ns_ref_inner_element($elements, $search_keys)) {
$output[] = $callback($inner_elements);
}
}
return $output;
}
/**
* Converts a simple search string into a multiple search sets.
*/
function ns_search_keys($search) {
$search_array = array();
foreach (explode(',', $search) as $i => $set) {
foreach (preg_split("/[\s]+/", $set, -1, PREG_SPLIT_NO_EMPTY) as $sub_set) {
$search_array[$i][] = is_numeric($sub_set) ? (int) $sub_set : $sub_set;
}
}
return $search_array;
}
/**
* Forms a reference to an inner element targeted by a search.
*
* @param $elements
* The parent element.
* @param $search
* An array of search keys pointing to a key member of the $elements.
*/
function &ns_ref_inner_element(&$elements, $search = array()) {
$indexes = ns_path_finder($elements, $search);
if ($indexes && end($search) == end($indexes)) {
$inner_elements = &$elements;
for ($index = reset($indexes); $index !== FALSE; $index = next($indexes)) {
$inner_elements = &$inner_elements[$index];
}
}
else {
$inner_elements = NULL;
}
return $inner_elements;
}
/**
* Returns a flat array mapping the traversed tree of the targeted search.
*
* @param $elements
* The typically large haystack.
* @param $search
* An array of paths to search by key.
* @param $found
* For internal use while in recursion.
*/
function ns_path_finder($elements, $search, $found = array()) {
$find = current($search);
foreach ($elements as $path => $sub_elements) {
// Ignore hash keys.
if ($path[0] === '#') {
continue;
}
// Increment if found.
if ($path === $find) {
next($search);
}
// Apply recursion and merge as it pulls out.
if ($inner_found = ns_path_finder($sub_elements, $search, $found)) {
$found = array_merge($found, array($path), $inner_found);
return $found;
}
// Found.
elseif ($path === $find) {
$found[] = $path;
return $found;
}
}
return FALSE;
}
@dvessel
Copy link
Author

dvessel commented Feb 6, 2011

Hrm, the time spent by ns_path_finder can accumulate on super large page arrays but I have no idea on how to cache it. Works well enough but beware on busy sites with a complex page array structure.

@dvessel
Copy link
Author

dvessel commented Feb 6, 2011

Updated ns_path_finder. It's about twice as fast without all the unneeded safety checks.

@johnvsc
Copy link

johnvsc commented Feb 7, 2011

These look awesome ! Bookmarking

@dvessel
Copy link
Author

dvessel commented Feb 7, 2011

Great! This is going to be part of the NineSixty theme. And don't forget to read Young Hahn's post on rules based theming. This bit of code isn't exactly rules based but imagine if we got to that point. We are about 10% there and I can already see how this can simplify things a good deal.

@johnvsc
Copy link

johnvsc commented Feb 8, 2011

You know what, I wrote this function for my RUNVSC theme to automate the ns() function:

function runvsc_build_main_classes(& $variables, $addclass = "") {
  $left = $variables['left'];
  $left_layout = $variables['layouts']['left']['grid'];
  $right = $variables['right'];
  $right_layout = $variables['layouts']['right']['grid'];
  $main_layout = $variables['layouts']['default']['container'];
  $container = "container-" . $main_layout ;

  if ($left && $right) {
    $value = $main_layout - $right_layout - $left_layout ;
    $grid = "grid-" . $value ;
    $classes = array($container, $grid) ;
  }
  else
    if ($left) {
      $value = $main_layout - $left_layout ;
      $grid = "grid-" . $value ;
      $classes = array($container, $grid) ;
    }
    else
      if ($right) {
        $value = $main_layout - $right_layout ;
        $grid = "grid-" . $value ;
        $classes = array($container, $grid) ;
      }
      else {
        $classes[] = runvsc_build_layout_classes($variables['layouts']) ;
  }
  $classes[] = $addclass ;
  $output = 'class="' . runvsc_implode_array($classes) . '"' ;
  return $output ;
}

But for the D7 version of RUNVSC, I want to make a layout manager -> where you can swap out CSS classes to control layout. I need to look at this (and you code above) in order to figure out a way to make this happen -> seems like we are thinking in the same direction!

@dvessel
Copy link
Author

dvessel commented Feb 8, 2011

I'm not sure exactly what that function is doing since I haven't seen the theme but one thing you can do dig into any element in the $page array and push classes into individual elements. I did a few simple experiments and it's possible to push grid classes from the page.tpl.php or "page" scope into any inner elements. Might be possible to have a massive layout manager from one place like a THEME_preprocess_page() shoving grid classes into individual nodes, blocks, etc…

I'll leave that to the smarter folks out there though. The though of any sort of 'manager' gives me a headache. :)

@dvessel
Copy link
Author

dvessel commented Mar 3, 2011

I got something better going on here: https://gist.github.com/852446

Similar idea but far more powerful using a class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment