Commit 0d8515de authored by webchick's avatar webchick

#552478 by pwolanin, samj, dropcube, and sun: Improve link/header API and...

#552478 by pwolanin, samj, dropcube, and sun: Improve link/header API and support on node/comment pages rel=canonical and rel=shortlink standards.
parent 3b2d24af
...@@ -149,6 +149,12 @@ Drupal 7.0, xxxx-xx-xx (development version) ...@@ -149,6 +149,12 @@ Drupal 7.0, xxxx-xx-xx (development version)
* Modules can specify how their data structure maps to RDF. * Modules can specify how their data structure maps to RDF.
* Added support for RDFa export of nodes, comments, terms, users, etc. and * Added support for RDFa export of nodes, comments, terms, users, etc. and
their fields. their fields.
- Search engine optimization and web linking:
* Added a rel="canonical" link on node and comment pages to prevent
duplicate content indexing by search engines.
* Added a default rel="shortlink" link on node and comment pages that
advertises a short link as an alternative URL to third-party services.
* Meta information is now alterable by all modules before rendering.
- Field API: - Field API:
* Custom data fields may be attached to nodes, users, comments and taxonomy * Custom data fields may be attached to nodes, users, comments and taxonomy
terms. terms.
......
...@@ -215,7 +215,14 @@ function _batch_progress_page_nojs() { ...@@ -215,7 +215,14 @@ function _batch_progress_page_nojs() {
$batch['url_options']['query']['op'] = $new_op; $batch['url_options']['query']['op'] = $new_op;
$url = url($batch['url'], $batch['url_options']); $url = url($batch['url'], $batch['url_options']);
drupal_add_html_head('<meta http-equiv="Refresh" content="0; URL=' . $url . '">'); $element = array(
'#tag' => 'meta',
'#attributes' => array(
'http-equiv' => 'Refresh',
'content' => '0; URL=' . $url,
),
);
drupal_add_html_head($element, 'batch_progress_meta_refresh');
return theme('progress_bar', array('percent' => $percentage, 'message' => $message)); return theme('progress_bar', array('percent' => $percentage, 'message' => $message));
} }
......
...@@ -280,23 +280,78 @@ function drupal_get_rdf_namespaces() { ...@@ -280,23 +280,78 @@ function drupal_get_rdf_namespaces() {
/** /**
* Add output to the head tag of the HTML page. * Add output to the head tag of the HTML page.
* *
* This function can be called as long the headers aren't sent. * This function can be called as long the headers aren't sent. Pass no
* arguments (or NULL for both) to retrieve the currently stored elements.
*
* @param $data
* A renderable array. If the '#type' key is not set then 'html_tag' will be
* added as the default '#type'.
* @param $key
* A unique string key to allow implementations of hook_html_head_alter() to
* identify the element in $data. Required if $data is not NULL.
*
* @return
* An array of all stored HEAD elements.
*
* @see theme_html_tag()
*/ */
function drupal_add_html_head($data = NULL) { function drupal_add_html_head($data = NULL, $key = NULL) {
$stored_head = &drupal_static(__FUNCTION__, ''); $stored_head = &drupal_static(__FUNCTION__);
if (!is_null($data)) { if (!isset($stored_head)) {
$stored_head .= $data . "\n"; // Make sure the defaults, including Content-Type, come first.
$stored_head = _drupal_default_html_head();
}
if (isset($data) && isset($key)) {
if (!isset($data['#type'])) {
$data['#type'] = 'html_tag';
}
$stored_head[$key] = $data;
} }
return $stored_head; return $stored_head;
} }
/** /**
* Retrieve output to be displayed in the head tag of the HTML page. * Returns elements that are always displayed in the HEAD tag of the HTML page.
*/
function _drupal_default_html_head() {
// Add default elements. Make sure the Content-Type comes first because the
// IE browser may be vulnerable to XSS via encoding attacks from any content
// that comes before this META tag, such as a TITLE tag.
$elements['system_meta_content_type'] = array(
'#type' => 'html_tag',
'#tag' => 'meta',
'#attributes' => array(
'http-equiv' => 'Content-Type',
'content' => 'text/html; charset=utf-8',
),
// Security: This always has to be output first.
'#weight' => -1000,
);
// Show Drupal and the major version number in the META GENERATOR tag.
// Get the major version.
list($version, ) = explode('.', VERSION);
$elements['system_meta_generator'] = array(
'#type' => 'html_tag',
'#tag' => 'meta',
'#attributes' => array(
'name' => 'Generator',
'content' => 'Drupal ' . $version . ' (http://drupal.org)',
),
);
// Also send the generator in the HTTP header.
$elements['system_meta_generator']['#attached']['drupal_add_http_header'][] = array('X-Generator', $elements['system_meta_generator']['#attributes']['content']);
return $elements;
}
/**
* Retrieve output to be displayed in the HEAD tag of the HTML page.
*/ */
function drupal_get_html_head() { function drupal_get_html_head() {
$output = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n"; $elements = drupal_add_html_head();
return $output . drupal_add_html_head(); drupal_alter('html_head', $elements);
return drupal_render($elements);
} }
/** /**
...@@ -319,10 +374,10 @@ function drupal_clear_path_cache() { ...@@ -319,10 +374,10 @@ function drupal_clear_path_cache() {
function drupal_add_feed($url = NULL, $title = '') { function drupal_add_feed($url = NULL, $title = '') {
$stored_feed_links = &drupal_static(__FUNCTION__, array()); $stored_feed_links = &drupal_static(__FUNCTION__, array());
if (!is_null($url) && !isset($stored_feed_links[$url])) { if (isset($url)) {
$stored_feed_links[$url] = theme('feed_icon', array('url' => $url, 'title' => $title)); $stored_feed_links[$url] = theme('feed_icon', array('url' => $url, 'title' => $title));
drupal_add_link(array('rel' => 'alternate', drupal_add_html_head_link(array('rel' => 'alternate',
'type' => 'application/rss+xml', 'type' => 'application/rss+xml',
'title' => $title, 'title' => $title,
'href' => $url)); 'href' => $url));
...@@ -2539,6 +2594,28 @@ function url_is_external($path) { ...@@ -2539,6 +2594,28 @@ function url_is_external($path) {
return $colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && filter_xss_bad_protocol($path, FALSE) == check_plain($path); return $colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && filter_xss_bad_protocol($path, FALSE) == check_plain($path);
} }
/**
* Format an attribute string for a HTTP header.
*
* @param $attributes
* An associative array of attributes such as 'rel'.
*
* @return
* A ; separated string ready for insertion in a HTTP header. No escaping is
* performed for HTML entities, so this string is not safe to be printed.
*
* @see drupal_add_http_header()
*/
function drupal_http_header_attributes(array $attributes = array()) {
foreach ($attributes as $attribute => &$data) {
if (is_array($data)) {
$data = implode(' ', $data);
}
$data = $attribute . '="' . $data . '"';
}
return $attributes ? ' ' . implode('; ', $attributes) : '';
}
/** /**
* Format an attribute string to insert in a tag. * Format an attribute string to insert in a tag.
* *
...@@ -2949,12 +3026,33 @@ function base_path() { ...@@ -2949,12 +3026,33 @@ function base_path() {
} }
/** /**
* Add a <link> tag to the page's HEAD. * Add a LINK tag with a distinct 'rel' attribute to the page's HEAD.
* *
* This function can be called as long the HTML header hasn't been sent. * This function can be called as long the HTML header hasn't been sent,
*/ * which on normal pages is up through the preprocess step of theme('html').
function drupal_add_link($attributes) { * Adding a link will overwrite a prior link with the exact same 'rel' and
drupal_add_html_head('<link' . drupal_attributes($attributes) . " />\n"); * 'href' attributes.
*
* @param $attributes
* Associative array of element attributes including 'href' and 'rel'.
* @param $header
* Optional flag to determine if a HTTP 'Link:' header should be sent.
*/
function drupal_add_html_head_link($attributes, $header = FALSE) {
$element = array(
'#tag' => 'link',
'#attributes' => $attributes,
);
$href = $attributes['href'];
if ($header) {
// Also add a HTTP header "Link:".
$href = '<' . check_plain($attributes['href']) . '>;';
unset($attributes['href']);
$element['#attached']['drupal_add_http_header'][] = array('Link', $href . drupal_http_header_attributes($attributes), TRUE);
}
drupal_add_html_head($element, 'drupal_add_html_head_link:' . $attributes['rel'] . ':' . $href);
} }
/** /**
...@@ -3140,7 +3238,15 @@ function drupal_get_css($css = NULL) { ...@@ -3140,7 +3238,15 @@ function drupal_get_css($css = NULL) {
} }
// If CSS preprocessing is off, we still need to output the styles. // If CSS preprocessing is off, we still need to output the styles.
// Additionally, go through any remaining styles if CSS preprocessing is on and output the non-cached ones. // Additionally, go through any remaining styles if CSS preprocessing is on
// and output the non-cached ones.
$css_element = array(
'#tag' => 'link',
'#attributes' => array(
'type' => 'text/css',
'rel' => 'stylesheet',
),
);
$rendered_css = array(); $rendered_css = array();
$inline_css = ''; $inline_css = '';
$external_css = ''; $external_css = '';
...@@ -3152,7 +3258,10 @@ function drupal_get_css($css = NULL) { ...@@ -3152,7 +3258,10 @@ function drupal_get_css($css = NULL) {
case 'file': case 'file':
// Depending on whether aggregation is desired, include the file. // Depending on whether aggregation is desired, include the file.
if (!$item['preprocess'] || !($is_writable && $preprocess_css)) { if (!$item['preprocess'] || !($is_writable && $preprocess_css)) {
$rendered_css[] = '<link type="text/css" rel="stylesheet" media="' . $item['media'] . '" href="' . file_create_url($item['data']) . $query_string . '" />'; $element = $css_element;
$element['#attributes']['media'] = $item['media'];
$element['#attributes']['href'] = file_create_url($item['data']) . $query_string;
$rendered_css[] = theme('html_tag', array('element' => $element));
} }
else { else {
$preprocess_items[$item['media']][] = $item; $preprocess_items[$item['media']][] = $item;
...@@ -3167,7 +3276,10 @@ function drupal_get_css($css = NULL) { ...@@ -3167,7 +3276,10 @@ function drupal_get_css($css = NULL) {
break; break;
case 'external': case 'external':
// Preprocessing for external CSS files is ignored. // Preprocessing for external CSS files is ignored.
$external_css .= '<link type="text/css" rel="stylesheet" media="' . $item['media'] . '" href="' . $item['data'] . '" />' . "\n"; $element = $css_element;
$element['#attributes']['media'] = $item['media'];
$element['#attributes']['href'] = $item['data'];
$external_css .= theme('html_tag', array('element' => $element));
break; break;
} }
} }
...@@ -3176,18 +3288,24 @@ function drupal_get_css($css = NULL) { ...@@ -3176,18 +3288,24 @@ function drupal_get_css($css = NULL) {
foreach ($preprocess_items as $media => $items) { foreach ($preprocess_items as $media => $items) {
// Prefix filename to prevent blocking by firewalls which reject files // Prefix filename to prevent blocking by firewalls which reject files
// starting with "ad*". // starting with "ad*".
$element = $css_element;
$element['#attributes']['media'] = $media;
$filename = 'css_' . md5(serialize($items) . $query_string) . '.css'; $filename = 'css_' . md5(serialize($items) . $query_string) . '.css';
$preprocess_file = file_create_url(drupal_build_css_cache($items, $filename)); $element['#attributes']['href'] = file_create_url(drupal_build_css_cache($items, $filename));
$rendered_css['preprocess'] .= '<link type="text/css" rel="stylesheet" media="' . $media . '" href="' . $preprocess_file . '" />' . "\n"; $rendered_css['preprocess'] .= theme('html_tag', array('element' => $element));
} }
} }
// Enclose the inline CSS with the style tag if required. // Enclose the inline CSS with the style tag if required.
if (!empty($inline_css)) { if (!empty($inline_css)) {
$inline_css = "\n" . '<style type="text/css">' . $inline_css .'</style>'; $element = $css_element;
$element['#tag'] = 'style';
$element['#value'] = $inline_css;
unset($element['#attributes']['rel']);
$inline_css = "\n" . theme('html_tag', array('element' => $element));
} }
// Output all the CSS files with the inline stylesheets showing up last. // Output all the CSS files with the inline stylesheets showing up last.
return implode("\n", $rendered_css) . $external_css . $inline_css; return implode($rendered_css) . $external_css . $inline_css;
} }
/** /**
...@@ -3668,7 +3786,7 @@ function drupal_get_js($scope = 'header', $javascript = NULL) { ...@@ -3668,7 +3786,7 @@ function drupal_get_js($scope = 'header', $javascript = NULL) {
$output = ''; $output = '';
$preprocessed = ''; $preprocessed = '';
$no_preprocess = ''; $no_preprocess = "\n";
$files = array(); $files = array();
$preprocess_js = (variable_get('preprocess_js', FALSE) && (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update')); $preprocess_js = (variable_get('preprocess_js', FALSE) && (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update'));
$directory = file_directory_path('public'); $directory = file_directory_path('public');
...@@ -3692,19 +3810,42 @@ function drupal_get_js($scope = 'header', $javascript = NULL) { ...@@ -3692,19 +3810,42 @@ function drupal_get_js($scope = 'header', $javascript = NULL) {
uasort($items, 'drupal_sort_weight'); uasort($items, 'drupal_sort_weight');
// Loop through the JavaScript to construct the rendered output. // Loop through the JavaScript to construct the rendered output.
$element = array(
'#tag' => 'script',
'#value' => '',
'#attributes' => array(
'type' => 'text/javascript',
),
);
foreach ($items as $item) { foreach ($items as $item) {
switch ($item['type']) { switch ($item['type']) {
case 'setting': case 'setting':
$output .= '<script type="text/javascript">' . $embed_prefix . 'jQuery.extend(Drupal.settings, ' . drupal_json_encode(call_user_func_array('array_merge_recursive', $item['data'])) . ");" . $embed_suffix . "</script>\n"; $js_element = $element;
$js_element['#value_prefix'] = $embed_prefix;
$js_element['#value'] = 'jQuery.extend(Drupal.settings, ' . drupal_json_encode(call_user_func_array('array_merge_recursive', $item['data'])) . ");";
$js_element['#value_suffix'] = $embed_suffix;
$output .= theme('html_tag', array('element' => $js_element));
break; break;
case 'inline': case 'inline':
$output .= '<script type="text/javascript"' . ($item['defer'] ? ' defer="defer"' : '') . '>' . $embed_prefix . $item['data'] . $embed_suffix . "</script>\n"; $js_element = $element;
if ($item['defer']) {
$js_element['#attributes']['defer'] = 'defer';
}
$js_element['#value_prefix'] = $embed_prefix;
$js_element['#value'] = $item['data'];
$js_element['#value_suffix'] = $embed_suffix;
$output .= theme('html_tag', array('element' => $js_element));
break; break;
case 'file': case 'file':
$js_element = $element;
if (!$item['preprocess'] || !$is_writable || !$preprocess_js) { if (!$item['preprocess'] || !$is_writable || !$preprocess_js) {
$no_preprocess .= '<script type="text/javascript"' . ($item['defer'] ? ' defer="defer"' : '') . ' src="' . file_create_url($item['data']) . ($item['cache'] ? $query_string : '?' . REQUEST_TIME) . "\"></script>\n"; if ($item['defer']) {
$js_element['#attributes']['defer'] = 'defer';
}
$js_element['#attributes']['src'] = file_create_url($item['data']) . ($item['cache'] ? $query_string : '?' . REQUEST_TIME);
$no_preprocess .= theme('html_tag', array('element' => $js_element));
} }
else { else {
$files[$item['data']] = $item; $files[$item['data']] = $item;
...@@ -3712,8 +3853,13 @@ function drupal_get_js($scope = 'header', $javascript = NULL) { ...@@ -3712,8 +3853,13 @@ function drupal_get_js($scope = 'header', $javascript = NULL) {
break; break;
case 'external': case 'external':
$js_element = $element;
// Preprocessing for external JavaScript files is ignored. // Preprocessing for external JavaScript files is ignored.
$output .= '<script type="text/javascript"' . ($item['defer'] ? ' defer="defer"' : '') . ' src="' . check_plain($item['data']) . "\"></script>\n"; if ($item['defer']) {
$js_element['#attributes']['defer'] = 'defer';
}
$js_element['#attributes']['src'] = $item['data'];
$output .= theme('html_tag', array('element' => $js_element));
break; break;
} }
} }
...@@ -3724,7 +3870,9 @@ function drupal_get_js($scope = 'header', $javascript = NULL) { ...@@ -3724,7 +3870,9 @@ function drupal_get_js($scope = 'header', $javascript = NULL) {
// starting with "ad*". // starting with "ad*".
$filename = 'js_' . md5(serialize($files) . $query_string) . '.js'; $filename = 'js_' . md5(serialize($files) . $query_string) . '.js';
$preprocess_file = file_create_url(drupal_build_js_cache($files, $filename)); $preprocess_file = file_create_url(drupal_build_js_cache($files, $filename));
$preprocessed .= '<script type="text/javascript" src="' . $preprocess_file . '"></script>' . "\n"; $js_element = $element;
$js_element['#attributes']['src'] = $preprocess_file;
$preprocessed .= theme('html_tag', array('element' => $js_element)) . "\n";
} }
// Keep the order of JS files consistent as some are preprocessed and others are not. // Keep the order of JS files consistent as some are preprocessed and others are not.
...@@ -5238,6 +5386,9 @@ function drupal_common_theme() { ...@@ -5238,6 +5386,9 @@ function drupal_common_theme() {
'indentation' => array( 'indentation' => array(
'variables' => array('size' => 1), 'variables' => array('size' => 1),
), ),
'html_tag' => array(
'render element' => 'element',
),
// from theme.maintenance.inc // from theme.maintenance.inc
'maintenance_page' => array( 'maintenance_page' => array(
'variables' => array('content' => NULL, 'show_messages' => TRUE), 'variables' => array('content' => NULL, 'show_messages' => TRUE),
......
...@@ -1878,6 +1878,48 @@ function theme_feed_icon($variables) { ...@@ -1878,6 +1878,48 @@ function theme_feed_icon($variables) {
} }
} }
/**
* Generate the output for a generic HTML tag with attributes.
*
* This theme function should be used for tags appearing in the HTML HEAD of a
* document (specified via the #tag property in the passed $element):
*
* @param $variables
* An associative array containing:
* - element: An associative array describing the tag:
* - #tag: The tag name to output. Typical tags added to the HTML HEAD:
* - meta: To provide meta information, such as a page refresh.
* - link: To refer to stylesheets and other contextual information.
* - script: To load JavaScript.
* - #attributes: (optional) An array of HTML attributes to apply to the
* tag.
* - #value: (optional) A string containing tag content, such as inline CSS.
* - #value_prefix: (optional) A string to prepend to #value, e.g. a CDATA
* wrapper prefix.
* - #value_suffix: (optional) A string to append to #value, e.g. a CDATA
* wrapper suffix.
*
* @ingroup themeable
*/
function theme_html_tag($variables) {
$element = $variables['element'];
if (!isset($element['#value'])) {
return '<' . $element['#tag'] . drupal_attributes($element['#attributes']) . " />\n";
}
else {
$output = '<' . $element['#tag'] . drupal_attributes($element['#attributes']) . '>';
if (isset($element['#value_prefix'])) {
$output .= $element['#value_prefix'];
}
$output .= $element['#value'];
if (isset($element['#value_suffix'])) {
$output .= $element['#value_suffix'];
}
$output .= '</' . $element['#tag'] . ">\n";
return $output;
}
}
/** /**
* Returns code that emits the 'more' link used on blocks. * Returns code that emits the 'more' link used on blocks.
* *
...@@ -2181,7 +2223,7 @@ function template_preprocess_html(&$variables) { ...@@ -2181,7 +2223,7 @@ function template_preprocess_html(&$variables) {
if (theme_get_setting('toggle_favicon')) { if (theme_get_setting('toggle_favicon')) {
$favicon = theme_get_setting('favicon'); $favicon = theme_get_setting('favicon');
$type = theme_get_setting('favicon_mimetype'); $type = theme_get_setting('favicon_mimetype');
drupal_add_html_head('<link rel="shortcut icon" href="' . check_url($favicon) . '" type="' . check_plain($type) . '" />'); drupal_add_html_head_link(array('rel' => 'shortcut icon', 'href' => check_url($favicon), 'type' => $type));
} }
// Construct page title. // Construct page title.
...@@ -2350,7 +2392,7 @@ function template_preprocess_maintenance_page(&$variables) { ...@@ -2350,7 +2392,7 @@ function template_preprocess_maintenance_page(&$variables) {
if (theme_get_setting('toggle_favicon')) { if (theme_get_setting('toggle_favicon')) {
$favicon = theme_get_setting('favicon'); $favicon = theme_get_setting('favicon');
$type = theme_get_setting('favicon_mimetype'); $type = theme_get_setting('favicon_mimetype');
drupal_add_html_head('<link rel="shortcut icon" href="' . check_url($favicon) . '" type="' . check_plain($type) . '" />'); drupal_add_html_head_link(array('rel' => 'shortcut icon', 'href' => check_url($favicon), 'type' => $type));
} }
global $theme; global $theme;
......
...@@ -940,21 +940,21 @@ function template_preprocess_book_navigation(&$variables) { ...@@ -940,21 +940,21 @@ function template_preprocess_book_navigation(&$variables) {
if ($prev = book_prev($book_link)) { if ($prev = book_prev($book_link)) {
$prev_href = url($prev['href']); $prev_href = url($prev['href']);
drupal_add_link(array('rel' => 'prev', 'href' => $prev_href)); drupal_add_html_head_link(array('rel' => 'prev', 'href' => $prev_href));
$variables['prev_url'] = $prev_href; $variables['prev_url'] = $prev_href;
$variables['prev_title'] = check_plain($prev['title']); $variables['prev_title'] = check_plain($prev['title']);
} }
if ($book_link['plid'] && $parent = book_link_load($book_link['plid'])) { if ($book_link['plid'] && $parent = book_link_load($book_link['plid'])) {
$parent_href = url($parent['href']); $parent_href = url($parent['href']);
drupal_add_link(array('rel' => 'up', 'href' => $parent_href)); drupal_add_html_head_link(array('rel' => 'up', 'href' => $parent_href));
$variables['parent_url'] = $parent_href; $variables['parent_url'] = $parent_href;
$variables['parent_title'] = check_plain($parent['title']); $variables['parent_title'] = check_plain($parent['title']);
} }
if ($next = book_next($book_link)) { if ($next = book_next($book_link)) {
$next_href = url($next['href']); $next_href = url($next['href']);
drupal_add_link(array('rel' => 'next', 'href' => $next_href)); drupal_add_html_head_link(array('rel' => 'next', 'href' => $next_href));
$variables['next_url'] = $next_href; $variables['next_url'] = $next_href;
$variables['next_title'] = check_plain($next['title']); $variables['next_title'] = check_plain($next['title']);
} }
......
...@@ -362,9 +362,6 @@ function comment_permalink($comment) { ...@@ -362,9 +362,6 @@ function comment_permalink($comment) {
$_GET['q'] = 'node/' . $node->nid; $_GET['q'] = 'node/' . $node->nid;
$_GET['page'] = $page; $_GET['page'] = $page;
// Set the node path as the canonical URL to prevent duplicate content.
drupal_add_link(array('rel' => 'canonical', 'href' => url('node/' . $node->nid)));
// Return the node view, this will show the correct comment in context. // Return the node view, this will show the correct comment in context.
return menu_execute_active_handler('node/' . $node->nid, FALSE); return menu_execute_active_handler('node/' . $node->nid, FALSE);
} }
......
...@@ -2152,6 +2152,10 @@ function node_page_view(stdClass $node) { ...@@ -2152,6 +2152,10 @@ function node_page_view(stdClass $node) {
if (isset($return['nodes'][$node->nid]['title'])) { if (isset($return['nodes'][$node->nid]['title'])) {
drupal_set_title($return['nodes'][$node->nid]['title']['items'][0]['#item']['value']); drupal_set_title($return['nodes'][$node->nid]['title']['items'][0]['#item']['value']);
} }
// Set the node path as the canonical URL to prevent duplicate content.
drupal_add_html_head_link(array('rel' => 'canonical', 'href' => url('node/' . $node->nid)), TRUE);
// Set the non-aliased path as a default shortlink.
drupal_add_html_head_link(array('rel' => 'shortlink', 'href' => url('node/' . $node->nid, array('alias' => TRUE))), TRUE);
return $return; return $return;
} }
......
...@@ -97,7 +97,14 @@ function openid_test_yadis_x_xrds_location() { ...@@ -97,7 +97,14 @@ function openid_test_yadis_x_xrds_location() {
* Menu callback; regular HTML page with <meta> element. * Menu callback; regular HTML page with <meta> element.
*/ */
function openid_test_yadis_http_equiv() { function openid_test_yadis_http_equiv() {
drupal_add_html_head('<meta http-equiv="X-XRDS-Location" content="' . url('openid-test/yadis/xrds', array('absolute' => TRUE)) . '" />'); $element = array(
'#tag' => 'meta',
'#attributes' => array(
'http-equiv' => 'X-XRDS-Location',
'content' => url('openid-test/yadis/xrds', array('absolute' => TRUE)),
),
);
drupal_add_html_head($element, 'openid_test_yadis_http_equiv');
return t('This page includes a &lt;meta equiv=...&gt; element containing the URL of an XRDS document.'); return t('This page includes a &lt;meta equiv=...&gt; element containing the URL of an XRDS document.');
} }
...@@ -105,7 +112,7 @@ function openid_test_yadis_http_equiv() { ...@@ -105,7 +112,7 @@ function openid_test_yadis_http_equiv() {
* Menu callback; regular HTML page with OpenID 1.0 <link> element. * Menu callback; regular HTML page with OpenID 1.0 <link> element.
*/ */
function openid_test_html_openid1() { function openid_test_html_openid1() {
drupal_add_html_head('<link rel="openid.server" href="' . url('openid-test/endpoint', array('absolute' => TRUE)) . '" />'); drupal_add_html_head_link(array('rel' => 'openid.server', 'href' => url('openid-test/endpoint', array('absolute' => TRUE))));
return t('This page includes a &lt;link rel=...&gt; element containing the URL of an OpenID Provider Endpoint.'); return t