Hello Everyone,

Honestly, I have been having the worst time finding the proper items for the Render Array.
This is the main page for it, and it has nothing useful in terms of telling us the options we can use.

If anyone, please, know where I can find the list of options, give me the freakin link!
My brain, is hurt from going in circular links...

Thank you,
Yousef.

Comments

Jaypan’s picture

What do you mean 'items'? What items? What are you stuck on?

YousefAB’s picture

Hey,

I mean the different possible options,
ex.

	$content['content'] = array(
		'testing' => array(
			'#type' => 'form',
			'#action' => 'books/add',
			'#method' => 'post',
			'#id' => 'add-book',
			
			'children' => array(
				'child' => array(
					'#type' => 'textfield',
					'#value' => t('Enter ISBN'),
					'#name' => 'isbn',
				),
			),
			
			'#prefix' => '<div>',
			'#suffix' => '</div>',
		),
	);

What are all the fields like '#type', '#action' etc.. that exists?
What are all the types like 'form', 'textfield', 'markup' etc.. that exist?

Like this should be the easiest thing to document... unless it is, but I can't find the page..
Can you help?

Thanks.

Jaypan’s picture

They are mostly arbitrary, which is why you aren't finding anything.
You can always use #markup, #prefix and #suffix,

Let's say I create a page. This page returns the name of a single user, themed accordingly. First, let's look at the situation where I want to return a message saying that no friends are found. I can use #markup, #prefix and #suffix:

return array
(
  'no_users_found' => array // They key is chosen by me. Something descriptive.
  (
    '#markup' => t('Sorry, no users were found'),
    '#prefix' => '<p>',
    '#suffix' => '</p>'.
  ),
);

I am returning a render array, and assigning it an arbitrary key ('no_users_found'). This key allows someone looking at the render array further down the line, say in hook_page_alter(), to know what they are looking at. By setting the message as the #markup, with the wrapping tags as #prefix and #suffix, the themer can come along and use different tags if they want, say H2 tags instead. Or they can change the message. They can even redefine or remove the entire section of this array if they want.

If you use the #theme attribute, you will also have to pass any values that the theme() function would expect. Let's look at theming usernames. If we were to use the theme() function to render a username, we would need to pass it a fully loaded $user object, like this:

$themed_username = theme('username', array('account' => $account));

We could even return that username using #markup:

return array
(
  'user_found' => array // They key is chosen by me. Something descriptive.
  (
    '#markup' => theme('username', array('account' => $account)),
    '#prefix' => '<p>',
    '#suffix' => '</p>'.
  ),
);

This will work, but the username is rendered right away, and there is no opportunity to change it. Or maybe somewhere else down the line, someone needs the User ID, but since it's been rendered, it's not available. In this case, we can instead use the #theme element, and pass the $account object, as #account:

return array
(
  'user_found' => array // They key is chosen by me. Something descriptive.
  (
    '#theme'  => 'username',
    '#account' => $account,
    '#prefix' => '<p>',
    '#suffix' => '</p>'.
  ),
);

In this above, I am passing the #theme (username), with the required elements for the theme (account), but adding a # to the start of the required elements (#account). If you go to the theme_username() page, you can see that there are other values that can also be passed: #name, #extra, #link_path etc. You can add any of these as necessary. By returning this value, the username is not rendered until the array is passed through render(), meaning that themers can alter it and/or use the data in the $account object, right up until the last possible moment before rendering (which should be the last thing done).

As you can see, the #attributes are determined by the expectations of the theme_function/template that will be used to render the array. Since any theme function can determine its own requirements, this means that the #attributes of a render array are up to the theme, and are entirely arbitrary, which is why you are not finding a list of them.

Finally, there is the #type attribute. When creating forms, the #type element can be used (along with the #theme element if one were to want), and this will require the user to include certain attributes (for example, checkboxes and radios will require the #options element). These also come with their own built-in default theming, which you can ignore. This theming can be overridden (for example, override theme_checkboxes(), but I will not be explaining that here.

Hopefully this gives you a better understanding of what is going on when you return a render array from a function.

YousefAB’s picture

Thank you very much for taking the time and making that reply,
They should post that on the document webpage of Render Array!

Okay, so just a follow up question,
Can we assume that most/all themes have implemented these functions: Default Theme Implementations

And we can use them without having to worry about the code breaking?

Again, thank you for the explanation,
Best Regards,
Yousef.

Jaypan’s picture

Yes, you can use render arrays for any of the themes you showed. You can also create your own theme functions and use these as well. For example, let's say I need to take a $user variable, and theme it as either the text 'me', or 'theme'. I first register a theme function with hook_theme():

function my_module_theme()
{
  return array
  (
    'me_or_them' => array
    (
      'variables' => array('account' => NULL),
    ),
  );
}

My theme function would something like this:

function theme_me_or_them($variables)
{
  global $user;

  $account = $variables['account'];
  return ($user->uid == $account->uid) ? t('Me') : t('Them');
}

So now, I can return a render array in any page callback that uses the above theme function:

return array
(
  'my page' => array
  (
    '#theme' => 'me_or_them',
    '#account' => $account,
    '#prefix' => '<p>' . t('This page was created by '),
    '#suffix' => '</p>'
  )
);

(Note, the above example isn't a very good real-world example, but should show the idea of registering your own theme functions).

YousefAB’s picture

Awesome,
Thank You!

er.pushpinderrana’s picture

Thanks!

Pushpinder Rana #pushpinderdrupal
Acquia Certified Drupal Expert

orbmantell’s picture

The reason the form API works is there is a form API reference page where someone can easily look up how to build a form. I appreciate the drive to use render arrays, but render arrays themselves are useless without the ability to EASILY understand their creation. As best I can tell (from Google, api.drupal.org, and the drupal.org search) the general consensus for how to create a div wrapper is using #prefix and #suffix. In reality (I believe, I have yet to find anything verifying this) the correct method is:

array (
  '#type' => 'html_tag',
  '#tag' => 'div',
);

I don't know who should be in charge of this, but the Drupal community would benefit greatly from the creation of a render array API reference page.

Jaypan’s picture

The code you showed is for creating a div. Creating a wrapper on an element is done using #prefix and #suffix. The render array api reference page is here: http://drupal.org/node/930760 (there is a link in the original post as well).

orbmantell’s picture

I understand the original post and your reply both link to the api page for render arrays... however my point (and that of the OP) is that render arrays are very poorly documented. The page you link to says

Looking through system_element_info() we see a pile of predefined #types, including page, form, html_tag, value, markup, link, fieldset and many more.

(buried far down in the text). My point is that the form api reference is a very clean and fast means of displaying all the options available to the form api, and that render arrays could use a similar page. It seems like having to dig through multiple pages of api references instead of having clear and concise documentation discourages the use of what is a very powerful system.

Jaypan’s picture

The problem is, as I mentioned earlier in this thread, render array options are for the most part arbitrary. They can be whatever you set them to be. So it's not something that can be documented, as there are an infinite number of possibilities. This is why there isn't, and for that matter, can't be, a clearly defined reference like there is with the Form API. There are a few system defined options, and I believe they are documented on the reference page.

Edit: To elaborate a little further, the reason why there is (and can be) a Form API reference is that the FAPI is a defined subset of render arrays, with a number of fixed options. These options are what you see documented on the FAPI reference page. Since render arrays as a whole however are an open system, there isn't really anything to document, other than the currently existing options, which as I mentioned above, are listed on the reference page.

Edit 2: I should add, I do feel your pain. I had a heck of a time wrapping my head around render arrays when I was first working with them, and felt a lot of frustration. The documentation could probably use some clean-up to help with this, and I've tried to do my bit by putting up the post in this thread trying to explain a little better how they work.

Mixologic’s picture

You can also use #theme_wrappers to define a theme function to wrap around the element in question.. which is far better than using #prefix or #suffix, since those are straight up strings, whereas #theme_wrappers could define a template file or a theme function - which once in place could be overridden easily in the future. But #prefix and #suffix will get the job done if you only need to set one or two elements that way. I have no idea why the api reference page says its 'rare to use it with #theme' - thats just unwarranted opinion injection - imo.

Jaypan’s picture

Good post, but:

I have no idea why the api reference page says its 'rare to use it with #theme' - thats just unwarranted opinion injection - imo.

Isn't that what you are doing here:

You can also use #theme_wrappers to define a theme function to wrap around the element in question.. which is far better than using #prefix or #suffix

#theme_wrappers have their place, but so do #prefix and #suffix. One isn't far better than the other, it just depends on what you are doing.