Issue #1858452 by Mile23: [meta] Examples projects without tests.
[project/examples.git] / theming_example / theming_example.module
1 <?php
2
3 /**
4 * @file
5 * Explains how a module declares theme functions, preprocess functions, and
6 * templates.
7 *
8 * The underlying approach is that a module should allow themes to do all
9 * rendering, but provide default implementations where appropriate.
10 *
11 * Modules are also expected to leave data as render arrays as long as possible,
12 * leaving rendering to theme functions and templates.
13 */
14
15 /**
16 * @defgroup theming_example Example: Theming
17 * @ingroup examples
18 * @{
19 * Example of Drupal theming.
20 *
21 * The theming_example module attempts to show how module developers can add
22 * theme functions to their projects so that themes can modify output.
23 *
24 * Module developers should to strive to avoid hard-wiring any HTML into the
25 * output of their code, this should all be done in theme functions.
26 *
27 * Starting with the first example, function 'theming_example_page()':
28 * the output is put into an array $content which is then fed to a theming
29 * function 'theme_theming_example_page()' which loops over the content,
30 * wrapping it in html in the process.
31 *
32 * In order to get function 'theme_theming_example_page()' recognized it needs
33 * to be registered with the module theme register function of the
34 * type 'hook_theme'.
35 *
36 * function 'theming_example_theme()' does this for this module.
37 * for details of what can be done in this hook see the link to api.drupal.org
38 *
39 * The functions 'theming_example_list_page()' and theming_example_order_form()
40 * work in the same way.
41 *
42 * In 'theme_theming_example_list_page()' the content is themed as an
43 * ordered list and given a class attribute 'theming_example_mylist' which
44 * is defined in theming_example.css
45 *
46 * In function 'theme_theming_example_order_form()' the title is loaded into a
47 * temporary variable '$title', deleted from the $form array and output
48 * wrapped in html. The rest of the form is wrapped in a div using '#prefix'
49 * and '#suffix'
50 *
51 * The theming functions can be copied to a theme's template.php, renaming
52 * appropriately, so if you theme is called 'mytheme' you would copy
53 * function 'theme_theming_example_page()'
54 * to
55 * function 'mytheme_theming_example_page()' in template.php and it will be
56 * used instead of the original.
57 *
58 * The fourth example shows the use of a template file
59 * 'theming_example_text_form.tpl.php'
60 * This file can be copied to a theme's folder and it will be used instead.
61 *
62 * This example also shows what can be done using Drupal's
63 * template_preprocess_HOOK method. In this case it modifies the output so
64 * that a themer can output the whole form or gain control over some of its
65 * parts in the template file.
66 */
67
68 /**
69 * Implements hook_menu().
70 *
71 * The @link menu_example.module Menu Example @endlink provides extensive
72 * examples for hook_menu().
73 */
74 function theming_example_menu() {
75 $items['examples/theming_example'] = array(
76 'title' => 'Theming Example',
77 'description' => 'Some theming examples.',
78 'page callback' => 'theming_example_page',
79 'access callback' => TRUE,
80 'access arguments' => array('access content'),
81 );
82 $items['examples/theming_example/theming_example_list_page'] = array(
83 'title' => 'Theming a list',
84 'page callback' => 'theming_example_list_page',
85 'access arguments' => array('access content'),
86 'weight' => 1,
87 );
88 $items['examples/theming_example/theming_example_select_form'] = array(
89 'title' => 'Theming a form (select form)',
90 'page callback' => 'drupal_get_form',
91 'page arguments' => array('theming_example_select_form'),
92 'access arguments' => array('access content'),
93 'weight' => 2,
94 );
95 $items['examples/theming_example/theming_example_text_form'] = array(
96 'title' => 'Theming a form (text form)',
97 'page callback' => 'drupal_get_form',
98 'page arguments' => array('theming_example_text_form'),
99 'access arguments' => array('access content'),
100 'weight' => 3,
101 );
102
103 return $items;
104
105 }
106
107 /**
108 * Implements hook_theme().
109 *
110 * Defines the theming capabilities provided by this module.
111 */
112 function theming_example_theme() {
113 return array(
114 'theming_example_content_array' => array(
115 // We use 'render element' when the item to be passed is a self-describing
116 // render array (it will have #theme_wrappers)
117 'render element' => 'element',
118 ),
119 'theming_example_list' => array(
120 // We use 'variables' when the item to be passed is an array whose
121 // structure must be described here.
122 'variables' => array(
123 'title' => NULL,
124 'items' => NULL,
125 ),
126 ),
127 'theming_example_select_form' => array(
128 'render element' => 'form',
129 ),
130 'theming_example_text_form' => array(
131 'render element' => 'form',
132 // In this one the rendering will be done by a template file
133 // (theming-example-text-form.tpl.php) instead of being rendered by a
134 // function. Note the use of dashes to separate words in place of
135 // underscores. The template file's extension is also left out so that
136 // it may be determined automatically depending on the template engine
137 // the site is using.
138 'template' => 'theming-example-text-form',
139 ),
140 );
141 }
142 /**
143 * Initial landing page explaining the use of the module.
144 *
145 * We create a render array and specify the theme to be used through the use
146 * of #theme_wrappers. With all output, we aim to leave the content as a
147 * render array just as long as possible, so that other modules (or the theme)
148 * can alter it.
149 *
150 * @see render_example.module
151 * @see form_example_elements.inc
152 */
153 function theming_example_page() {
154 $content[] = t('Some examples of pages and forms that are run through theme functions.');
155 $content[] = l(t('Simple page with a list'), 'examples/theming_example/theming_example_list_page');
156 $content[] = l(t('Simple form 1'), 'examples/theming_example/theming_example_select_form');
157 $content[] = l(t('Simple form 2'), 'examples/theming_example/theming_example_text_form');
158 $content['#theme_wrappers'] = array('theming_example_content_array');
159 return $content;
160 }
161
162 /**
163 * The list page callback.
164 *
165 * An example page where the output is supplied as an array which is themed
166 * into a list and styled with css.
167 *
168 * In this case we'll use the core-provided theme_item_list as a #theme_wrapper.
169 * Any theme need only override theme_item_list to change the behavior.
170 */
171 function theming_example_list_page() {
172 $items = array(
173 t('First item'),
174 t('Second item'),
175 t('Third item'),
176 t('Fourth item'),
177 );
178
179 // First we'll create a render array that simply uses theme_item_list.
180 $title = t("A list returned to be rendered using theme('item_list')");
181 $build['render_version'] = array(
182 // We use #theme here instead of #theme_wrappers because theme_item_list()
183 // is the classic type of theme function that does not just assume a
184 // render array, but instead has its own properties (#type, #title, #items).
185 '#theme' => 'item_list',
186 // '#type' => 'ul', // The default type is 'ul'
187 // We can easily make sure that a css or js file is present using #attached.
188 '#attached' => array('css' => array(drupal_get_path('module', 'theming_example') . '/theming_example.css')),
189 '#title' => $title,
190 '#items' => $items,
191 '#attributes' => array('class' => array('render-version-list')),
192 );
193
194 // Now we'll create a render array which uses our own list formatter,
195 // theme('theming_example_list').
196 $title = t("The same list rendered by theme('theming_example_list')");
197 $build['our_theme_function'] = array(
198 '#theme' => 'theming_example_list',
199 '#attached' => array('css' => array(drupal_get_path('module', 'theming_example') . '/theming_example.css')),
200 '#title' => $title,
201 '#items' => $items,
202 );
203 return $build;
204 }
205
206
207 /**
208 * A simple form that displays a select box and submit button.
209 *
210 * This form will be be themed by the 'theming_example_select_form' theme
211 * handler.
212 */
213 function theming_example_select_form($form, &$form_state) {
214 $options = array(
215 'newest_first' => t('Newest first'),
216 'newest_last' => t('Newest last'),
217 'edited_first' => t('Edited first'),
218 'edited_last' => t('Edited last'),
219 'by_name' => t('By name'),
220 );
221 $form['choice'] = array(
222 '#type' => 'select',
223 '#options' => $options,
224 '#title' => t('Choose which ordering you want'),
225 );
226 $form['submit'] = array(
227 '#type' => 'submit',
228 '#value' => t('Go'),
229 );
230 return $form;
231 }
232
233 /**
234 * Submit handler for the select form.
235 *
236 * @param array $form
237 * Form API form array.
238 * @param array $form_state
239 * Form API form state array.
240 */
241 function theming_example_select_form_submit($form, &$form_state) {
242 drupal_set_message(t('You chose %input', array('%input' => $form_state['values']['choice'])));
243 }
244
245 /**
246 * A simple form that displays a textfield and submit button.
247 *
248 * This form will be rendered by theme('form') (theme_form() by default)
249 * because we do not provide a theme function for it here.
250 */
251 function theming_example_text_form($form, &$form_state) {
252 $form['text'] = array(
253 '#type' => 'textfield',
254 '#title' => t('Please input something!'),
255 '#required' => TRUE,
256 );
257 $form['submit'] = array(
258 '#type' => 'submit',
259 '#value' => t('Go'),
260 );
261 return $form;
262 }
263
264 /**
265 * Submit handler for the text form.
266 *
267 * @param array $form
268 * Form API form array.
269 * @param array $form_state
270 * Form API form state array.
271 */
272 function theming_example_text_form_submit($form, &$form_state) {
273 drupal_set_message(t('You entered %input', array('%input' => $form_state['values']['text'])));
274 }
275
276
277 /**
278 * Theme a simple content array.
279 *
280 * This theme function uses the newer recommended format where a single
281 * render array is provided to the theme function.
282 */
283 function theme_theming_example_content_array($variables) {
284 $element = $variables['element'];
285 $output = '';
286 foreach (element_children($element) as $count) {
287 if (!$count) {
288 // The first paragraph is bolded.
289 $output .= '<p><strong>' . $element[$count] . '</strong></p>';
290 }
291 else {
292 // Following paragraphs are just output as routine paragraphs.
293 $output .= '<p>' . $element[$count] . '</p>';
294 }
295 }
296 return $output;
297 }
298
299 /**
300 * Theming a simple list.
301 *
302 * This is just a simple wrapper around theme('item_list') but it's worth
303 * showing how a custom theme function can be implemented.
304 *
305 * @see theme_item_list()
306 */
307 function theme_theming_example_list($variables) {
308 $title = $variables['title'];
309 $items = $variables['items'];
310
311 // Add the title to the list theme and
312 // state the list type. This defaults to 'ul'.
313 // Add a css class so that you can modify the list styling.
314 // We'll just call theme('item_list') to render.
315 $variables = array(
316 'items' => $items,
317 'title' => $title,
318 'type' => 'ol',
319 'attributes' => array('class' => 'theming-example-list'),
320 );
321 $output = theme('item_list', $variables);
322 return $output;
323 }
324
325 /**
326 * Theming a simple form.
327 *
328 * Since our form is named theming_example_select_form(), the default
329 * #theme function applied to is will be 'theming_example_select_form'
330 * if it exists. The form could also have specified a different
331 * #theme.
332 *
333 * Here we collect the title, theme it manually and
334 * empty the form title. We also wrap the form in a div.
335 */
336 function theme_theming_example_select_form($variables) {
337 $form = $variables['form'];
338 $title = $form['choice']['#title'];
339 $form['choice']['#title'] = '';
340 $output = '<strong>' . $title . '</strong>';
341 $form['choice']['#prefix'] = '<div class="container-inline">';
342 $form['submit']['#suffix'] = '</div>';
343 $output .= drupal_render_children($form);
344 return $output;
345 }
346
347 /**
348 * Implements template_preprocess().
349 *
350 * We prepare variables for use inside the theming-example-text-form.tpl.php
351 * template file.
352 *
353 * In this example, we create a couple new variables, 'text_form' and
354 * 'text_form_content', that clean up the form output. Drupal will turn the
355 * array keys in the $variables array into variables for use in the template.
356 *
357 * So $variables['text_form'] becomes available as $text_form in the template.
358 *
359 * @see theming-example-text-form.tpl.php
360 */
361 function template_preprocess_theming_example_text_form(&$variables) {
362 $variables['text_form_content'] = array();
363 $text_form_hidden = array();
364
365 // Each form element is rendered and saved as a key in $text_form_content, to
366 // give the themer the power to print each element independently in the
367 // template file. Hidden form elements have no value in the theme, so they
368 // are grouped into a single element.
369 foreach (element_children($variables['form']) as $key) {
370 $type = $variables['form'][$key]['#type'];
371 if ($type == 'hidden' || $type == 'token') {
372 $text_form_hidden[] = drupal_render($variables['form'][$key]);
373 }
374 else {
375 $variables['text_form_content'][$key] = drupal_render($variables['form'][$key]);
376 }
377 }
378 $variables['text_form_content']['hidden'] = implode($text_form_hidden);
379
380 // The entire form is then saved in the $text_form variable, to make it easy
381 // for the themer to print the whole form.
382 $variables['text_form'] = implode($variables['text_form_content']);
383 }
384 /**
385 * @} End of "defgroup theming_example".
386 */