Basically I want to be able to nest html element inside anchor, using render array.

Then, I could have this code inside hook_block_view.

  $anchor = 'yahoo' => array(
    '#type' => 'link',
    '#href' => 'http://example.com/',
    '#title' => array(
      '#theme' => 'image',
      '#path' => 'http://example.com/logo.png',
    ),
    '#options' => array(
      'attributes' => array(),
    ),
  );

#title is populated with render array for img element.

I don't know if this could be implemented in some other way, but my current implementation is by applying a patch on drupal_pre_render_link.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dozymoe’s picture

Issue summary: View changes

s/by of/,/

dozymoe’s picture

On second thought, it would be better if I can have,

 'title' => Array (BLEH BLAH UGH),

rendered first then have it converted to,

 '#title' => HTML-MARKUP,

somehow. :S

This is for #theme whose arguments expect simple text or predefined html markup.

dozymoe’s picture

Title: Arguments to theme as renderable array in a render array. Allow better nesting of html element. » Allow anchor to have children, change #title in drupal_pre_render_link to be render array
Status: Needs work » Active
Issue tags: -Novice

I came up with:

function drupal_pre_render_map_childs($element) {
  foreach ($element['#map_childs'] as $key => $values) {
    // We expected $values to be an array.
    $element[$key] = drupal_render_children($element, $values);
  }
  return $element;
}

Basically it merges several children listed in $values part of #map_childs into a single key. Presumable, like in the sample below, points to #text, an argument that goes to theme_link.

Implemented here.

// Implement hook_block_view
function MYMODULE_block_view($delta = '') {
  $block = array();

  switch ($delta) {
    case 'external_links':
      $block['subject'] = t('External Links');
      $block['content'] = array(
        'one_linky' => array(

          '#pre_render' => array('drupal_pre_render_map_childs'),
          '#map_childs' => array(
            // Render title and store the result in #text.
            '#text' => array('title'),
          ),

          '#theme' => 'link',
          '#path' => 'http://MYLINKBLAH',
          '#options' => array(
            'attributes' => array(),
            'html' => TRUE,
          ),
          // Normally we expect #text to be defined here, and its
          // value can only be either plain text (or literal string) or html.

          'title' => array(
            '#theme' => 'image',
            '#path' => 'http://MYIMAGEBLAH',
          ),

        ),
      );
      break;
  }
  return $block;
}

Doesn't work with #type such as '#type' => 'link' because the #pre_render clashed. I think. Dunno.

So it's fine if we just use '#theme' => 'link'.

PS: I see similar applications in drupal_pre_render_links.

dozymoe’s picture

Title: Allow anchor to have children, change #title in drupal_pre_render_link to be render array » Arguments to theme as renderable array in a render array. Allow better nesting of html element.
Status: Active » Needs review
FileSize
2.24 KB

Changed title and marked as need review.

Also served as snippet page, if anybody is interested. :3

dozymoe’s picture

Status: Needs review » Needs work

Failed at theme_links() XD. Bummer.

dozymoe’s picture

The following code works, with a little exception.

function drupal_pre_render_map_childs($element) {
  foreach ($element['#map_childs'] as $key => $value) {
    if (is_array($value)) {
      $element[$key] = drupal_render_children($element, $value);
    }
    else {
      drupal_render_children($element[$value]);
      $element[$key] = $element[$value];
    }
  }
  return $element;
}

The change is, for theme function that expects the argument to be an array, #map_childs' value has to be a string, not array. This tells drupal_pre_render_map_childs not to set the argument with results from drupal_render_children(), but link it by reference to $element[$value], thus result in an array that we wanted.

Example follows.

$markup = array(
  '#pre_render' => array('drupal_pre_render_map_childs'),
  '#map_childs' => array(
    '#links' => 'my_links',
  ),
  '#theme_wrappers' => array('container'),
  '#attributes' => array(),
  '#theme' => 'links',
  'my_links' => array(
    'first_link' => array(
      'href' => 'http://MYLINKBLAH/',
      'html' => '1',
      '#pre_render' => array('drupal_pre_render_map_childs'),
      '#map_childs' => array(
        'title' => array('my_image'),
      ),
      'my_image' => array(
        '#theme' => 'image',
        '#path' => 'http://MYLINKBLAH/MYIMAGE.jpg',
      ),
    ),
  ),
);

Notice that html value is '1' (a string). Either wise that element is passed to element_children() and produce warnings.

Warning: Invalid argument supplied for foreach() in element_children()

Ugly as hell, but in my use case, it works. 0.0b

PS: set html to value '1' or '0' works as if it is set with TRUE and FALSE. Me need to spent more time debugging. This could replace drupal_pre_render_links() with a bit more functionality.

dozymoe’s picture

Simple fix, modified drupal_render() in includes/common.inc, before:

  // Early-return nothing if user does not have access.
  if (empty($elements) || (isset($elements['#access']) && !$elements['#access'])) {
    return;
  }

And after:

  // Early-return nothing if user does not have access.
  if (!is_array($elements) || (isset($elements['#access']) && !$elements['#access'])) {
    return;
  }

Maybe I should add !count($elements) in there. Hm.

First attempt on OnionHead _failed_.

dozymoe’s picture

Title: Allow anchor to have children, change #title in drupal_pre_render_link to be render array » Arguments to theme as renderable array in a render array. Allow better nesting of html element.
Status: Active » Needs review
FileSize
2.69 KB

In case somebody is waiting for this to hit need review ~(‾-‾")~, forgotten to mark the patch listed, no changes made.

Reduce possible hick-up to one.

That is if the theme function requires 2 or more level-deep array-argument.

Might become a problem since drupal_render_children automatically adds #printed and #children element.

This two elements can be an unexpected baggage in the theme function.

dozymoe’s picture

Status: Needs work » Needs review
xjm’s picture

Status: Needs review » Needs work
Issue tags: +Novice

Thanks for your work on this patch. I'm not sure whether we'd want to include this callback in core or not; however, here are some suggestions for cleaning up the patch a little.

+++ b/includes/common.incundefined
@@ -7465,3 +7465,65 @@ function drupal_get_filetransfer_info() {
+ * #pre_render callback that will drupal_render() specified children to
+ * become the value of another child.

Let's try to fit this on one line. Maybe:

Pre-render callback: renders specified children as the value of another child.

Also, generally, let's change "childs" to "children" everywhere in the patch.

Finally, note that the Drupal 8.x patch will need to be rerolled, because the core directory structure for Drupal 8 has now changed. (For more information, see #22336: Move all core Drupal files under a /core folder to improve usability and upgrades). When the patch has been rerolled, please set the issue back to "Needs Review."

Tagging as novice for the task of rerolling the Drupal 8.x patch.

If you need help rerolling this patch, you can come to core office hours or ask in #drupal-gitsupport on IRC.

dozymoe’s picture

Status: Needs review » Needs work
Issue tags: +Novice

A quick note:

This function uses iteration, can cause deep iteration if the render array is nested too deep.

PHP is not optimized to do iteration, I think.

Unless, drupal uses SPL iterators, then this might just work for the general cases.

I'll try to find the link where I've read that, in stackoverflow.com IIRC.

musicnode’s picture

Assigned: Unassigned » musicnode
Status: Needs work » Needs review
FileSize
2.18 KB
2.7 KB

Re-rolled per xjm's suggestions:

1) Changed comment to: Pre-render callback: renders specified children as the value of another child.
2) Changed change "childs" to "children" everywhere in the patch.

musicnode’s picture

Assigned: musicnode » Unassigned

Uploaded the patch, so unassign.

dozymoe’s picture

Status: Needs review » Closed (works as designed)

Closed as works as designed I guess, to be removed from the issue queue active priority.

dozymoe’s picture

Issue summary: View changes

heh. s/of//