1. 8.2.x core/includes/theme.inc
  2. 8.0.x core/includes/theme.inc
  3. 8.1.x core/includes/theme.inc
  4. 8.3.x core/includes/theme.inc
  5. 4.6.x includes/theme.inc
  6. 4.7.x includes/theme.inc
  7. 5.x includes/theme.inc
  8. 6.x includes/theme.inc
  9. 7.x includes/theme.inc

The theme system, which controls the output of Drupal.

The theme system allows for nearly all output of the Drupal system to be customized by user themes.

See also

<a href="http://drupal.org/node/171179">Theme guide</a>

Themeable functions

File

includes/theme.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * The theme system, which controls the output of Drupal.
  5. *
  6. * The theme system allows for nearly all output of the Drupal system to be
  7. * customized by user themes.
  8. *
  9. * @see <a href="http://drupal.org/node/171179">Theme guide</a>
  10. * @see themeable
  11. */
  12. /**
  13. * @name Content markers
  14. * @{
  15. * Markers used by theme_mark() and node_mark() to designate content.
  16. * @see theme_mark(), node_mark()
  17. */
  18. define('MARK_READ', 0);
  19. define('MARK_NEW', 1);
  20. define('MARK_UPDATED', 2);
  21. /**
  22. * @} End of "Content markers".
  23. */
  24. /**
  25. * Initialize the theme system by loading the theme.
  26. *
  27. */
  28. function init_theme() {
  29. global $theme, $user, $custom_theme, $theme_engine, $theme_key;
  30. // If $theme is already set, assume the others are set, too, and do nothing
  31. if (isset($theme)) {
  32. return;
  33. }
  34. drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
  35. $themes = list_themes();
  36. // Only select the user selected theme if it is available in the
  37. // list of enabled themes.
  38. $theme = !empty($user->theme) && !empty($themes[$user->theme]->status) ? $user->theme : variable_get('theme_default', 'garland');
  39. // Allow modules to override the present theme... only select custom theme
  40. // if it is available in the list of installed themes.
  41. $theme = $custom_theme && $themes[$custom_theme] ? $custom_theme : $theme;
  42. // Store the identifier for retrieving theme settings with.
  43. $theme_key = $theme;
  44. // If we're using a style, load its appropriate theme,
  45. // which is stored in the style's description field.
  46. // Also add the stylesheet using drupal_add_css().
  47. // Otherwise, load the theme.
  48. if (strpos($themes[$theme]->filename, '.css')) {
  49. // File is a style; loads its CSS.
  50. // Set theme to its template/theme
  51. drupal_add_css($themes[$theme]->filename, 'theme');
  52. $theme = basename(dirname($themes[$theme]->description));
  53. }
  54. else {
  55. // File is a template/theme
  56. // Load its CSS, if it exists
  57. if (file_exists($stylesheet = dirname($themes[$theme]->filename) .'/style.css')) {
  58. drupal_add_css($stylesheet, 'theme');
  59. }
  60. }
  61. if (strpos($themes[$theme]->filename, '.theme')) {
  62. // file is a theme; include it
  63. include_once './' . $themes[$theme]->filename;
  64. }
  65. elseif (strpos($themes[$theme]->description, '.engine')) {
  66. // file is a template; include its engine
  67. include_once './' . $themes[$theme]->description;
  68. $theme_engine = basename($themes[$theme]->description, '.engine');
  69. if (function_exists($theme_engine .'_init')) {
  70. call_user_func($theme_engine .'_init', $themes[$theme]);
  71. }
  72. }
  73. }
  74. /**
  75. * Provides a list of currently available themes.
  76. *
  77. * @param $refresh
  78. * Whether to reload the list of themes from the database.
  79. * @return
  80. * An array of the currently available themes.
  81. */
  82. function list_themes($refresh = FALSE) {
  83. static $list;
  84. if ($refresh) {
  85. unset($list);
  86. }
  87. if (!$list) {
  88. $list = array();
  89. $result = db_query("SELECT * FROM {system} WHERE type = 'theme'");
  90. while ($theme = db_fetch_object($result)) {
  91. if (file_exists($theme->filename)) {
  92. $list[$theme->name] = $theme;
  93. }
  94. }
  95. }
  96. return $list;
  97. }
  98. /**
  99. * Provides a list of currently available theme engines
  100. *
  101. * @param $refresh
  102. * Whether to reload the list of themes from the database.
  103. * @return
  104. * An array of the currently available theme engines.
  105. */
  106. function list_theme_engines($refresh = FALSE) {
  107. static $list;
  108. if ($refresh) {
  109. unset($list);
  110. }
  111. if (!$list) {
  112. $list = array();
  113. $result = db_query("SELECT * FROM {system} WHERE type = 'theme_engine' AND status = '1' ORDER BY name");
  114. while ($engine = db_fetch_object($result)) {
  115. if (file_exists($engine->filename)) {
  116. $list[$engine->name] = $engine;
  117. }
  118. }
  119. }
  120. return $list;
  121. }
  122. /**
  123. * Generate the themed representation of a Drupal object.
  124. *
  125. * All requests for themed functions must go through this function. It examines
  126. * the request and routes it to the appropriate theme function. If the current
  127. * theme does not implement the requested function, then the current theme
  128. * engine is checked. If neither the engine nor theme implement the requested
  129. * function, then the base theme function is called.
  130. *
  131. * For example, to retrieve the HTML that is output by theme_page($output), a
  132. * module should call theme('page', $output).
  133. *
  134. * @param $function
  135. * The name of the theme function to call.
  136. * @param ...
  137. * Additional arguments to pass along to the theme function.
  138. * @return
  139. * An HTML string that generates the themed output.
  140. */
  141. function theme() {
  142. static $functions;
  143. $args = func_get_args();
  144. $function = array_shift($args);
  145. if (!isset($functions[$function])) {
  146. $functions[$function] = theme_get_function($function);
  147. }
  148. if ($functions[$function]) {
  149. $output = call_user_func_array($functions[$function], $args);
  150. // Add final markup to the full page.
  151. if ($function == 'page' || $function == 'book_export_html') {
  152. $output = drupal_final_markup($output);
  153. }
  154. return $output;
  155. }
  156. }
  157. /**
  158. * Determine if a theme function exists, and if so return which one was found.
  159. *
  160. * @param $function
  161. * The name of the theme function to test.
  162. * @return
  163. * The name of the theme function that should be used, or FALSE if no function exists.
  164. */
  165. function theme_get_function($function) {
  166. global $theme, $theme_engine;
  167. // Because theme() is called a lot, calling init_theme() only to have it
  168. // smartly return is a noticeable performance hit. Don't do it.
  169. if (!isset($theme)) {
  170. init_theme();
  171. }
  172. if (($theme != '') && function_exists($theme .'_'. $function)) {
  173. // call theme function
  174. return $theme .'_'. $function;
  175. }
  176. elseif (($theme != '') && isset($theme_engine) && function_exists($theme_engine .'_'. $function)) {
  177. // call engine function
  178. return $theme_engine .'_'. $function;
  179. }
  180. elseif (function_exists('theme_'. $function)){
  181. // call Drupal function
  182. return 'theme_'. $function;
  183. }
  184. return FALSE;
  185. }
  186. /**
  187. * Return the path to the currently selected theme.
  188. */
  189. function path_to_theme() {
  190. global $theme;
  191. if (!isset($theme)) {
  192. init_theme();
  193. }
  194. $themes = list_themes();
  195. return dirname($themes[$theme]->filename);
  196. }
  197. /**
  198. * Return the path to the currently selected engine.
  199. */
  200. function path_to_engine() {
  201. global $theme, $theme_engine;
  202. if (!isset($theme)) {
  203. init_theme();
  204. }
  205. $engines = list_theme_engines();
  206. return dirname($engines[$theme_engine]->filename);
  207. }
  208. /**
  209. * Retrieve an associative array containing the settings for a theme.
  210. *
  211. * The final settings are arrived at by merging the default settings,
  212. * the site-wide settings, and the settings defined for the specific theme.
  213. * If no $key was specified, only the site-wide theme defaults are retrieved.
  214. *
  215. * The default values for each of settings are also defined in this function.
  216. * To add new settings, add their default values here, and then add form elements
  217. * to system_theme_settings() in system.module.
  218. *
  219. * @param $key
  220. * The template/style value for a given theme.
  221. *
  222. * @return
  223. * An associative array containing theme settings.
  224. */
  225. function theme_get_settings($key = NULL) {
  226. $defaults = array(
  227. 'mission' => '',
  228. 'default_logo' => 1,
  229. 'logo_path' => '',
  230. 'default_favicon' => 1,
  231. 'favicon_path' => '',
  232. 'toggle_logo' => 1,
  233. 'toggle_favicon' => 1,
  234. 'toggle_name' => 1,
  235. 'toggle_search' => 1,
  236. 'toggle_slogan' => 0,
  237. 'toggle_mission' => 1,
  238. 'toggle_node_user_picture' => 0,
  239. 'toggle_comment_user_picture' => 0,
  240. );
  241. if (module_exists('node')) {
  242. foreach (node_get_types() as $type => $name) {
  243. $defaults['toggle_node_info_' . $type] = 1;
  244. }
  245. }
  246. $settings = array_merge($defaults, variable_get('theme_settings', array()));
  247. if ($key) {
  248. $settings = array_merge($settings, variable_get(str_replace('/', '_', 'theme_'. $key .'_settings'), array()));
  249. }
  250. // Only offer search box if search.module is enabled.
  251. if (!module_exists('search') || !user_access('search content')) {
  252. $settings['toggle_search'] = 0;
  253. }
  254. return $settings;
  255. }
  256. /**
  257. * Retrieve a setting for the current theme.
  258. * This function is designed for use from within themes & engines
  259. * to determine theme settings made in the admin interface.
  260. *
  261. * Caches values for speed (use $refresh = TRUE to refresh cache)
  262. *
  263. * @param $setting_name
  264. * The name of the setting to be retrieved.
  265. *
  266. * @param $refresh
  267. * Whether to reload the cache of settings.
  268. *
  269. * @return
  270. * The value of the requested setting, NULL if the setting does not exist.
  271. */
  272. function theme_get_setting($setting_name, $refresh = FALSE) {
  273. global $theme_key;
  274. static $settings;
  275. if (empty($settings) || $refresh) {
  276. $settings = theme_get_settings($theme_key);
  277. $themes = list_themes();
  278. $theme_object = $themes[$theme_key];
  279. if ($settings['mission'] == '') {
  280. $settings['mission'] = variable_get('site_mission', '');
  281. }
  282. if (!$settings['toggle_mission']) {
  283. $settings['mission'] = '';
  284. }
  285. if ($settings['toggle_logo']) {
  286. if ($settings['default_logo']) {
  287. $settings['logo'] = base_path() . dirname($theme_object->filename) .'/logo.png';
  288. }
  289. elseif ($settings['logo_path']) {
  290. $settings['logo'] = base_path() . $settings['logo_path'];
  291. }
  292. }
  293. if ($settings['toggle_favicon']) {
  294. if ($settings['default_favicon']) {
  295. if (file_exists($favicon = dirname($theme_object->filename) .'/favicon.ico')) {
  296. $settings['favicon'] = base_path() . $favicon;
  297. }
  298. else {
  299. $settings['favicon'] = base_path() . 'misc/favicon.ico';
  300. }
  301. }
  302. elseif ($settings['favicon_path']) {
  303. $settings['favicon'] = base_path() . $settings['favicon_path'];
  304. }
  305. else {
  306. $settings['toggle_favicon'] = FALSE;
  307. }
  308. }
  309. }
  310. return isset($settings[$setting_name]) ? $settings[$setting_name] : NULL;
  311. }
  312. /**
  313. * @defgroup themeable Themeable functions
  314. * @{
  315. * Functions that display HTML, and which can be customized by themes.
  316. *
  317. * All functions that produce HTML for display should be themeable. This means
  318. * that they should be named with the theme_ prefix, and invoked using theme()
  319. * rather than being called directly. This allows themes to override the display
  320. * of any Drupal object.
  321. *
  322. * The theme system is described and defined in theme.inc.
  323. */
  324. /**
  325. * Formats text for emphasized display in a placeholder inside a sentence.
  326. * Used automatically by t().
  327. *
  328. * @param $text
  329. * The text to format (plain-text).
  330. * @return
  331. * The formatted text (html).
  332. */
  333. function theme_placeholder($text) {
  334. return '<em>'. check_plain($text) .'</em>';
  335. }
  336. /**
  337. * Return an entire Drupal page displaying the supplied content.
  338. *
  339. * @param $content
  340. * A string to display in the main content area of the page.
  341. * @return
  342. * A string containing the entire HTML page.
  343. */
  344. function theme_page($content) {
  345. // Get blocks before so that they can alter the header (JavaScript, Stylesheets etc.)
  346. $blocks = theme('blocks', 'all');
  347. $output = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
  348. $output .= '<html xmlns="http://www.w3.org/1999/xhtml">';
  349. $output .= '<head>';
  350. $output .= ' <title>'. (drupal_get_title() ? strip_tags(drupal_get_title()) : variable_get('site_name', 'Drupal')) .'</title>';
  351. $output .= drupal_get_html_head();
  352. $output .= drupal_get_css();
  353. $output .= drupal_get_js();
  354. $output .= ' </head>';
  355. $output .= ' <body style="background-color: #fff; color: #000;">';
  356. $output .= '<table border="0" cellspacing="4" cellpadding="4"><tr><td style="vertical-align: top; width: 170px;">';
  357. $output .= $blocks;
  358. $output .= '</td><td style="vertical-align: top;">';
  359. $output .= theme('breadcrumb', drupal_get_breadcrumb());
  360. $output .= '<h1>' . drupal_get_title() . '</h1>';
  361. if ($tabs = theme('menu_local_tasks')) {
  362. $output .= $tabs;
  363. }
  364. $output .= theme('help');
  365. $output .= theme('status_messages');
  366. $output .= "\n<!-- begin content -->\n";
  367. $output .= $content;
  368. $output .= drupal_get_feeds();
  369. $output .= "\n<!-- end content -->\n";
  370. $output .= '</td></tr></table>';
  371. $output .= theme('closure');
  372. $output .= '</body></html>';
  373. return $output;
  374. }
  375. function theme_maintenance_page($content, $messages = TRUE, $partial = FALSE) {
  376. drupal_set_header('Content-Type: text/html; charset=utf-8');
  377. drupal_set_html_head('<style type="text/css" media="all">@import "'. base_path() .'misc/maintenance.css";</style>');
  378. drupal_set_html_head('<style type="text/css" media="all">@import "'. base_path() . drupal_get_path('module', 'system') .'/defaults.css";</style>');
  379. drupal_set_html_head('<style type="text/css" media="all">@import "'. base_path() . drupal_get_path('module', 'system') .'/system.css";</style>');
  380. drupal_set_html_head('<link rel="shortcut icon" href="'. base_path() .'misc/favicon.ico" type="image/x-icon" />');
  381. $output = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
  382. $output .= '<html xmlns="http://www.w3.org/1999/xhtml">';
  383. $output .= '<head>';
  384. $output .= ' <title>'. strip_tags(drupal_get_title()) .'</title>';
  385. $output .= drupal_get_html_head();
  386. $output .= drupal_get_js();
  387. $output .= '</head>';
  388. $output .= '<body>';
  389. $output .= '<h1>' . drupal_get_title() . '</h1>';
  390. if ($messages) {
  391. $output .= theme('status_messages');
  392. }
  393. $output .= "\n<!-- begin content -->\n";
  394. $output .= $content;
  395. $output .= "\n<!-- end content -->\n";
  396. if (!$partial) {
  397. $output .= '</body></html>';
  398. }
  399. return $output;
  400. }
  401. function theme_install_page($content) {
  402. drupal_set_header('Content-Type: text/html; charset=utf-8');
  403. drupal_add_css('misc/maintenance.css', 'module', 'all', FALSE);
  404. drupal_set_html_head('<link rel="shortcut icon" href="'. base_path() .'misc/favicon.ico" type="image/x-icon" />');
  405. $output = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
  406. $output .= '<html xmlns="http://www.w3.org/1999/xhtml">';
  407. $output .= '<head>';
  408. $output .= ' <title>'. strip_tags(drupal_get_title()) .'</title>';
  409. $output .= drupal_get_html_head();
  410. $output .= drupal_get_css();
  411. $output .= drupal_get_js();
  412. $output .= '</head>';
  413. $output .= '<body>';
  414. $output .= '<h1>' . drupal_get_title() . '</h1>';
  415. $messages = drupal_set_message();
  416. if (isset($messages['error'])) {
  417. $title = count($messages['error']) > 1 ? st('The following errors must be resolved before you can continue the installation process') : st('The following error must be resolved before you can continue the installation process');
  418. $output .= '<h3>' .$title. ':</h3>';
  419. $output .= theme('status_messages', 'error');
  420. }
  421. if (isset($messages['status'])) {
  422. $warnings = count($messages['status']) > 1 ? st('The following installation warnings should be carefully reviewed, but in most cases may be safely ignored') : st('The following installation warning should be carefully reviewed, but in most cases may be safely ignored');
  423. $output .= '<h4>' .$title. ':</h4>';
  424. $output .= theme('status_messages', 'status');
  425. }
  426. $output .= "\n<!-- begin content -->\n";
  427. $output .= $content;
  428. $output .= "\n<!-- end content -->\n";
  429. $output .= '</body></html>';
  430. return $output;
  431. }
  432. /**
  433. * Return a themed set of status and/or error messages. The messages are grouped
  434. * by type.
  435. *
  436. * @param $display
  437. * (optional) Set to 'status' or 'error' to display only messages of that type.
  438. *
  439. * @return
  440. * A string containing the messages.
  441. */
  442. function theme_status_messages($display = NULL) {
  443. $output = '';
  444. foreach (drupal_get_messages($display) as $type => $messages) {
  445. $output .= "<div class=\"messages $type\">\n";
  446. if (count($messages) > 1) {
  447. $output .= " <ul>\n";
  448. foreach ($messages as $message) {
  449. $output .= ' <li>'. $message ."</li>\n";
  450. }
  451. $output .= " </ul>\n";
  452. }
  453. else {
  454. $output .= $messages[0];
  455. }
  456. $output .= "</div>\n";
  457. }
  458. return $output;
  459. }
  460. /**
  461. * Return a themed set of links.
  462. *
  463. * @param $links
  464. * A keyed array of links to be themed.
  465. * @param $attributes
  466. * A keyed array of attributes
  467. * @return
  468. * A string containing an unordered list of links.
  469. */
  470. function theme_links($links, $attributes = array('class' => 'links')) {
  471. $output = '';
  472. if (count($links) > 0) {
  473. $output = '<ul'. drupal_attributes($attributes) .'>';
  474. $num_links = count($links);
  475. $i = 1;
  476. foreach ($links as $key => $link) {
  477. $class = $key;
  478. // Automatically add a class to each link and also to each LI
  479. if (isset($link['attributes']) && isset($link['attributes']['class'])) {
  480. $link['attributes']['class'] .= ' ' . $key;
  481. }
  482. else {
  483. $link['attributes']['class'] = $key;
  484. }
  485. // Add first and last classes to the list of links to help out themers.
  486. $extra_class = '';
  487. if ($i == 1) {
  488. $extra_class .= 'first ';
  489. }
  490. if ($i == $num_links) {
  491. $extra_class .= 'last ';
  492. }
  493. $output .= '<li '. drupal_attributes(array('class' => $extra_class . $class)) .'>';
  494. // Is the title HTML?
  495. $html = isset($link['html']) && $link['html'];
  496. // Initialize fragment and query variables.
  497. $link['query'] = isset($link['query']) ? $link['query'] : NULL;
  498. $link['fragment'] = isset($link['fragment']) ? $link['fragment'] : NULL;
  499. if (isset($link['href'])) {
  500. $output .= l($link['title'], $link['href'], $link['attributes'], $link['query'], $link['fragment'], FALSE, $html);
  501. }
  502. else if ($link['title']) {
  503. //Some links are actually not links, but we wrap these in <span> for adding title and class attributes
  504. if (!$html) {
  505. $link['title'] = check_plain($link['title']);
  506. }
  507. $output .= '<span'. drupal_attributes($link['attributes']) .'>'. $link['title'] .'</span>';
  508. }
  509. $i++;
  510. $output .= "</li>\n";
  511. }
  512. $output .= '</ul>';
  513. }
  514. return $output;
  515. }
  516. /**
  517. * Return a themed image.
  518. *
  519. * @param $path
  520. * Either the path of the image file (relative to base_path()) or a full URL.
  521. * @param $alt
  522. * The alternative text for text-based browsers.
  523. * @param $title
  524. * The title text is displayed when the image is hovered in some popular browsers.
  525. * @param $attributes
  526. * Associative array of attributes to be placed in the img tag.
  527. * @param $getsize
  528. * If set to TRUE, the image's dimension are fetched and added as width/height attributes.
  529. * @return
  530. * A string containing the image tag.
  531. */
  532. function theme_image($path, $alt = '', $title = '', $attributes = NULL, $getsize = TRUE) {
  533. if (!$getsize || (is_file($path) && (list($width, $height, $type, $image_attributes) = @getimagesize($path)))) {
  534. $attributes = drupal_attributes($attributes);
  535. $url = (url($path) == $path) ? $path : (base_path() . $path);
  536. return '<img src="'. check_url($url) .'" alt="'. check_plain($alt) .'" title="'. check_plain($title) .'" '. $image_attributes . $attributes .' />';
  537. }
  538. }
  539. /**
  540. * Return a themed breadcrumb trail.
  541. *
  542. * @param $breadcrumb
  543. * An array containing the breadcrumb links.
  544. * @return a string containing the breadcrumb output.
  545. */
  546. function theme_breadcrumb($breadcrumb) {
  547. if (!empty($breadcrumb)) {
  548. return '<div class="breadcrumb">'. implode(' » ', $breadcrumb) .'</div>';
  549. }
  550. }
  551. /**
  552. * Return a themed help message.
  553. *
  554. * @return a string containing the helptext for the current page.
  555. */
  556. function theme_help() {
  557. if ($help = menu_get_active_help()) {
  558. return '<div class="help">'. $help .'</div>';
  559. }
  560. }
  561. /**
  562. * Return a themed node.
  563. *
  564. * @param $node
  565. * An object providing all relevant information for displaying a node:
  566. * - $node->nid: The ID of the node.
  567. * - $node->type: The content type (story, blog, forum...).
  568. * - $node->title: The title of the node.
  569. * - $node->created: The creation date, as a UNIX timestamp.
  570. * - $node->teaser: A shortened version of the node body.
  571. * - $node->body: The entire node contents.
  572. * - $node->changed: The last modification date, as a UNIX timestamp.
  573. * - $node->uid: The ID of the author.
  574. * - $node->username: The username of the author.
  575. * @param $teaser
  576. * Whether to display the teaser only, as on the main page.
  577. * @param $page
  578. * Whether to display the node as a standalone page. If TRUE, do not display
  579. * the title because it will be provided by the menu system.
  580. * @return
  581. * A string containing the node output.
  582. */
  583. function theme_node($node, $teaser = FALSE, $page = FALSE) {
  584. if (!$node->status) {
  585. $output = '<div class="node-unpublished">';
  586. }
  587. if (module_exists('taxonomy')) {
  588. $terms = taxonomy_link('taxonomy terms', $node);
  589. }
  590. if ($page == 0) {
  591. $output .= t('!title by !name', array('!title' => '<h2 class="title">'. check_plain($node->title) .'</h2>', '!name' => theme('username', $node)));
  592. }
  593. else {
  594. $output .= t('by !name', array('!name' => theme('username', $node)));
  595. }
  596. if (count($terms)) {
  597. $output .= ' <small>('. theme('links', $terms) .')</small><br />';
  598. }
  599. if ($teaser && $node->teaser) {
  600. $output .= $node->teaser;
  601. }
  602. else {
  603. $output .= $node->body;
  604. }
  605. if ($node->links) {
  606. $output .= '<div class="links">'. theme('links', $node->links) .'</div>';
  607. }
  608. if (!$node->status) {
  609. $output .= '</div>';
  610. }
  611. return $output;
  612. }
  613. /**
  614. * Return a themed submenu, typically displayed under the tabs.
  615. *
  616. * @param $links
  617. * An array of links.
  618. */
  619. function theme_submenu($links) {
  620. return '<div class="submenu">'. implode(' | ', $links) .'</div>';
  621. }
  622. /**
  623. * Return a themed table.
  624. *
  625. * @param $header
  626. * An array containing the table headers. Each element of the array can be
  627. * either a localized string or an associative array with the following keys:
  628. * - "data": The localized title of the table column.
  629. * - "field": The database field represented in the table column (required if
  630. * user is to be able to sort on this column).
  631. * - "sort": A default sort order for this column ("asc" or "desc").
  632. * - Any HTML attributes, such as "colspan", to apply to the column header cell.
  633. * @param $rows
  634. * An array of table rows. Every row is an array of cells, or an associative
  635. * array with the following keys:
  636. * - "data": an array of cells
  637. * - Any HTML attributes, such as "class", to apply to the table row.
  638. *
  639. * Each cell can be either a string or an associative array with the following keys:
  640. * - "data": The string to display in the table cell.
  641. * - "header": Indicates this cell is a header.
  642. * - Any HTML attributes, such as "colspan", to apply to the table cell.
  643. *
  644. * Here's an example for $rows:
  645. * @verbatim
  646. * $rows = array(
  647. * // Simple row
  648. * array(
  649. * 'Cell 1', 'Cell 2', 'Cell 3'
  650. * ),
  651. * // Row with attributes on the row and some of its cells.
  652. * array(
  653. * 'data' => array('Cell 1', array('data' => 'Cell 2', 'colspan' => 2)), 'class' => 'funky'
  654. * )
  655. * );
  656. * @endverbatim
  657. *
  658. * @param $attributes
  659. * An array of HTML attributes to apply to the table tag.
  660. * @param $caption
  661. * A localized string to use for the <caption> tag.
  662. * @return
  663. * An HTML string representing the table.
  664. */
  665. function theme_table($header, $rows, $attributes = array(), $caption = NULL) {
  666. $output = '<table'. drupal_attributes($attributes) .">\n";
  667. if (isset($caption)) {
  668. $output .= '<caption>'. $caption ."</caption>\n";
  669. }
  670. // Format the table header:
  671. if (count($header)) {
  672. $ts = tablesort_init($header);
  673. // HTML requires that the thead tag has tr tags in it follwed by tbody
  674. // tags. Using ternary operator to check and see if we have any rows.
  675. $output .= (count($rows) ? ' <thead><tr>' : ' <tr>');
  676. foreach ($header as $cell) {
  677. $cell = tablesort_header($cell, $header, $ts);
  678. $output .= _theme_table_cell($cell, TRUE);
  679. }
  680. // Using ternary operator to close the tags based on whether or not there are rows
  681. $output .= (count($rows) ? " </tr></thead>\n" : "</tr>\n");
  682. }
  683. // Format the table rows:
  684. if (count($rows)) {
  685. $output .= "<tbody>\n";
  686. $flip = array('even' => 'odd', 'odd' => 'even');
  687. $class = 'even';
  688. foreach ($rows as $number => $row) {
  689. $attributes = array();
  690. // Check if we're dealing with a simple or complex row
  691. if (isset($row['data'])) {
  692. foreach ($row as $key => $value) {
  693. if ($key == 'data') {
  694. $cells = $value;
  695. }
  696. else {
  697. $attributes[$key] = $value;
  698. }
  699. }
  700. }
  701. else {
  702. $cells = $row;
  703. }
  704. // Add odd/even class
  705. $class = $flip[$class];
  706. if (isset($attributes['class'])) {
  707. $attributes['class'] .= ' '. $class;
  708. }
  709. else {
  710. $attributes['class'] = $class;
  711. }
  712. // Build row
  713. $output .= ' <tr'. drupal_attributes($attributes) .'>';
  714. $i = 0;
  715. foreach ($cells as $cell) {
  716. $cell = tablesort_cell($cell, $header, $ts, $i++);
  717. $output .= _theme_table_cell($cell);
  718. }
  719. $output .= " </tr>\n";
  720. }
  721. $output .= "</tbody>\n";
  722. }
  723. $output .= "</table>\n";
  724. return $output;
  725. }
  726. /**
  727. * Returns a header cell for tables that have a select all functionality.
  728. */
  729. function theme_table_select_header_cell() {
  730. drupal_add_js(array('tableSelect' => array('selectAll' => t('Select all rows in this table'), 'selectNone' => t('Deselect all rows in this table'))), 'setting');
  731. drupal_add_js('misc/tableselect.js');
  732. return array('class' => 'select-all');
  733. }
  734. /**
  735. * Return a themed sort icon.
  736. *
  737. * @param $style
  738. * Set to either asc or desc. This sets which icon to show.
  739. * @return
  740. * A themed sort icon.
  741. */
  742. function theme_tablesort_indicator($style) {
  743. if ($style == "asc"){
  744. return theme('image', 'misc/arrow-asc.png', t('sort icon'), t('sort ascending'));
  745. }
  746. else {
  747. return theme('image', 'misc/arrow-desc.png', t('sort icon'), t('sort descending'));
  748. }
  749. }
  750. /**
  751. * Return a themed box.
  752. *
  753. * @param $title
  754. * The subject of the box.
  755. * @param $content
  756. * The content of the box.
  757. * @param $region
  758. * The region in which the box is displayed.
  759. * @return
  760. * A string containing the box output.
  761. */
  762. function theme_box($title, $content, $region = 'main') {
  763. $output = '<h2 class="title">'. $title .'</h2><div>'. $content .'</div>';
  764. return $output;
  765. }
  766. /**
  767. * Return a themed block.
  768. *
  769. * You can style your blocks by defining .block (all blocks),
  770. * .block-<i>module</i> (all blocks of module <i>module</i>), and
  771. * \#block-<i>module</i>-<i>delta</i> (specific block of module <i>module</i>
  772. * with delta <i>delta</i>) in your theme's CSS.
  773. *
  774. * @param $block
  775. * An object populated with fields from the "blocks" database table
  776. * ($block->module, $block->delta ...) and fields returned by
  777. * <i>module</i>_block('view') ($block->subject, $block->content, ...).
  778. * @return
  779. * A string containing the block output.
  780. */
  781. function theme_block($block) {
  782. $output = "<div class=\"block block-$block->module\" id=\"block-$block->module-$block->delta\">\n";
  783. $output .= " <h2 class=\"title\">$block->subject</h2>\n";
  784. $output .= " <div class=\"content\">$block->content</div>\n";
  785. $output .= "</div>\n";
  786. return $output;
  787. }
  788. /**
  789. * Return a themed marker, useful for marking new or updated
  790. * content.
  791. *
  792. * @param $type
  793. * Number representing the marker type to display
  794. * @see MARK_NEW, MARK_UPDATED, MARK_READ
  795. * @return
  796. * A string containing the marker.
  797. */
  798. function theme_mark($type = MARK_NEW) {
  799. global $user;
  800. if ($user->uid) {
  801. if ($type == MARK_NEW) {
  802. return ' <span class="marker">'. t('new') .'</span>';
  803. }
  804. else if ($type == MARK_UPDATED) {
  805. return ' <span class="marker">'. t('updated') .'</span>';
  806. }
  807. }
  808. }
  809. /**
  810. * Return a themed list of items.
  811. *
  812. * @param $items
  813. * An array of items to be displayed in the list. If an item is a string,
  814. * then it is used as is. If an item is an array, then the "data" element of
  815. * the array is used as the contents of the list item. If an item is an array
  816. * with a "children" element, those children are displayed in a nested list.
  817. * All other elements are treated as attributes of the list item element.
  818. * @param $title
  819. * The title of the list.
  820. * @param $type
  821. * The type of list to return (e.g. "ul", "ol")
  822. * @param $attributes
  823. * The attributes applied to the list element.
  824. * @return
  825. * A string containing the list output.
  826. */
  827. function theme_item_list($items = array(), $title = NULL, $type = 'ul', $attributes = NULL) {
  828. $output = '<div class="item-list">';
  829. if (isset($title)) {
  830. $output .= '<h3>'. $title .'</h3>';
  831. }
  832. if (!empty($items)) {
  833. $output .= "<$type" . drupal_attributes($attributes) . '>';
  834. foreach ($items as $item) {
  835. $attributes = array();
  836. $children = array();
  837. if (is_array($item)) {
  838. foreach ($item as $key => $value) {
  839. if ($key == 'data') {
  840. $data = $value;
  841. }
  842. elseif ($key == 'children') {
  843. $children = $value;
  844. }
  845. else {
  846. $attributes[$key] = $value;
  847. }
  848. }
  849. }
  850. else {
  851. $data = $item;
  852. }
  853. if (count($children) > 0) {
  854. $data .= theme_item_list($children, NULL, $type, $attributes); // Render nested list
  855. }
  856. $output .= '<li' . drupal_attributes($attributes) . '>'. $data .'</li>';
  857. }
  858. $output .= "</$type>";
  859. }
  860. $output .= '</div>';
  861. return $output;
  862. }
  863. /**
  864. * Returns code that emits the 'more help'-link.
  865. */
  866. function theme_more_help_link($url) {
  867. return '<div class="more-help-link">' . t('[<a href="@link">more help...</a>]', array('@link' => check_url($url))) . '</div>';
  868. }
  869. /**
  870. * Return code that emits an XML icon.
  871. */
  872. function theme_xml_icon($url) {
  873. if ($image = theme('image', 'misc/xml.png', t('XML feed'), t('XML feed'))) {
  874. return '<a href="'. check_url($url) .'" class="xml-icon">'. $image. '</a>';
  875. }
  876. }
  877. /**
  878. * Return code that emits an feed icon.
  879. */
  880. function theme_feed_icon($url) {
  881. if ($image = theme('image', 'misc/feed.png', t('Syndicate content'), t('Syndicate content'))) {
  882. return '<a href="'. check_url($url) .'" class="feed-icon">'. $image. '</a>';
  883. }
  884. }
  885. /**
  886. * Execute hook_footer() which is run at the end of the page right before the
  887. * close of the body tag.
  888. *
  889. * @param $main (optional)
  890. * Whether the current page is the front page of the site.
  891. * @return
  892. * A string containing the results of the hook_footer() calls.
  893. */
  894. function theme_closure($main = 0) {
  895. $footer = module_invoke_all('footer', $main);
  896. return implode("\n", $footer) . drupal_get_js('footer');
  897. }
  898. /**
  899. * Return a set of blocks available for the current user.
  900. *
  901. * @param $region
  902. * Which set of blocks to retrieve.
  903. * @return
  904. * A string containing the themed blocks for this region.
  905. */
  906. function theme_blocks($region) {
  907. $output = '';
  908. if ($list = block_list($region)) {
  909. foreach ($list as $key => $block) {
  910. // $key == <i>module</i>_<i>delta</i>
  911. $output .= theme('block', $block);
  912. }
  913. }
  914. // Add any content assigned to this region through drupal_set_content() calls.
  915. $output .= drupal_get_content($region);
  916. return $output;
  917. }
  918. /**
  919. * Format a username.
  920. *
  921. * @param $object
  922. * The user object to format, usually returned from user_load().
  923. * @return
  924. * A string containing an HTML link to the user's page if the passed object
  925. * suggests that this is a site user. Otherwise, only the username is returned.
  926. */
  927. function theme_username($object) {
  928. if ($object->uid && $object->name) {
  929. // Shorten the name when it is too long or it will break many tables.
  930. if (drupal_strlen($object->name) > 20) {
  931. $name = drupal_substr($object->name, 0, 15) .'...';
  932. }
  933. else {
  934. $name = $object->name;
  935. }
  936. if (user_access('access user profiles')) {
  937. $output = l($name, 'user/'. $object->uid, array('title' => t('View user profile.')));
  938. }
  939. else {
  940. $output = check_plain($name);
  941. }
  942. }
  943. else if ($object->name) {
  944. // Sometimes modules display content composed by people who are
  945. // not registered members of the site (e.g. mailing list or news
  946. // aggregator modules). This clause enables modules to display
  947. // the true author of the content.
  948. if ($object->homepage) {
  949. $output = l($object->name, $object->homepage);
  950. }
  951. else {
  952. $output = check_plain($object->name);
  953. }
  954. $output .= ' ('. t('not verified') .')';
  955. }
  956. else {
  957. $output = variable_get('anonymous', t('Anonymous'));
  958. }
  959. return $output;
  960. }
  961. function theme_progress_bar($percent, $message) {
  962. $output = '<div id="progress" class="progress">';
  963. $output .= '<div class="percentage">'. $percent .'%</div>';
  964. $output .= '<div class="status">'. $message .'</div>';
  965. $output .= '<div class="bar"><div class="filled" style="width: '. $percent .'%"></div></div>';
  966. $output .= '</div>';
  967. return $output;
  968. }
  969. /**
  970. * @} End of "defgroup themeable".
  971. */
  972. function _theme_table_cell($cell, $header = FALSE) {
  973. $attributes = '';
  974. if (is_array($cell)) {
  975. $data = $cell['data'];
  976. $header |= isset($cell['header']);
  977. unset($cell['data']);
  978. unset($cell['header']);
  979. $attributes = drupal_attributes($cell);
  980. }
  981. else {
  982. $data = $cell;
  983. }
  984. if ($header) {
  985. $output = "<th$attributes>$data</th>";
  986. }
  987. else {
  988. $output = "<td$attributes>$data</td>";
  989. }
  990. return $output;
  991. }

Functions

Namesort descending Description
init_theme Initialize the theme system by loading the theme.
list_themes Provides a list of currently available themes.
list_theme_engines Provides a list of currently available theme engines
path_to_engine Return the path to the currently selected engine.
path_to_theme Return the path to the currently selected theme.
theme Generate the themed representation of a Drupal object.
theme_block Return a themed block.
theme_blocks Return a set of blocks available for the current user.
theme_box Return a themed box.
theme_breadcrumb Return a themed breadcrumb trail.
theme_closure Execute hook_footer() which is run at the end of the page right before the close of the body tag.
theme_feed_icon Return code that emits an feed icon.
theme_get_function Determine if a theme function exists, and if so return which one was found.
theme_get_setting Retrieve a setting for the current theme. This function is designed for use from within themes & engines to determine theme settings made in the admin interface.
theme_get_settings Retrieve an associative array containing the settings for a theme.
theme_help Return a themed help message.
theme_image Return a themed image.
theme_install_page
theme_item_list Return a themed list of items.
theme_links Return a themed set of links.
theme_maintenance_page
theme_mark Return a themed marker, useful for marking new or updated content.
theme_more_help_link Returns code that emits the 'more help'-link.
theme_node Return a themed node.
theme_page Return an entire Drupal page displaying the supplied content.
theme_placeholder Formats text for emphasized display in a placeholder inside a sentence. Used automatically by t().
theme_progress_bar
theme_status_messages Return a themed set of status and/or error messages. The messages are grouped by type.
theme_submenu Return a themed submenu, typically displayed under the tabs.
theme_table Return a themed table.
theme_tablesort_indicator Return a themed sort icon.
theme_table_select_header_cell Returns a header cell for tables that have a select all functionality.
theme_username Format a username.
theme_xml_icon Return code that emits an XML icon.
_theme_table_cell

Constants

Namesort descending Description
MARK_NEW
MARK_READ @name Content markers
MARK_UPDATED