Commit 6e50221d authored by Dave Reid's avatar Dave Reid
Browse files

by Dave Reid: Initial context API and UI rewrite.

parent b2c89320
......@@ -8,6 +8,204 @@
* @ingroup xmlsitemap
*/
function xmlsitemap_sitemap_list_form() {
// Build the 'Update options' form.
$operations = array();
foreach (module_invoke_all('xmlsitemap_sitemap_operations') as $operation => $operation_info) {
$operations[$operation] = $operation_info['label'];
}
asort($operations);
$form['options'] = array(
'#type' => 'fieldset',
'#title' => t('Update options'),
'#prefix' => '<div class="container-inline">',
'#suffix' => '</div>',
);
$form['options']['operation'] = array(
'#type' => 'select',
'#options' => $operations,
'#default_value' => 'update',
);
$form['options']['submit'] = array(
'#type' => 'submit',
'#value' => t('Update'),
'#validate' => array('xmlsitemap_sitemap_list_validate'),
'#submit' => array('xmlsitemap_sitemap_list_submit'),
);
$query = db_select('xmlsitemap_sitemap');
$query->fields('xmlsitemap_sitemap', array('smid'));
$smids = $query->execute()->fetchCol();
$contexts = xmlsitemap_get_context_info();
$header = array();
$header['url'] = array('data' => t('URL'), 'field' => 'url');
foreach ($contexts as $context_key => $context_info) {
if (!empty($context_info['summary callback'])) {
$header['context_' . $context_key] = $context_info['label'];
}
}
$header['updated'] = array('data' => t('Last updated'), 'field' => 'updated');
$header['links'] = array('data' => t('Links'), 'field' => 'links');
$header['chunks'] = array('data' => t('Pages'), 'field' => 'chunks');
$header['operations'] = array('data' => t('Operations'));
$options = array();
$destination = drupal_get_destination();
foreach ($smids as $smid) {
$sitemap = xmlsitemap_sitemap_load($smid);
$sitemap['uri'] = xmlsitemap_sitemap_uri($sitemap);
$options[$smid]['url'] = array(
'data' => array(
'#type' => 'link',
'#title' => url($sitemap['uri']['path'], $sitemap['uri']['options']),
'#href' => $sitemap['uri']['path'],
'#options' => $sitemap['uri']['options'],
),
);
foreach ($contexts as $context_key => $context_info) {
$options[$smid]['context_' . $context_key] = _xmlsitemap_sitemap_context_summary($sitemap, $context_key, $context_info);
}
$options[$smid]['updated'] = $sitemap['updated'] ? format_date($sitemap['updated'], 'short') : t('Never');
$options[$smid]['links'] = $sitemap['updated'] ? $sitemap['links'] : '-';
$options[$smid]['chunks'] = $sitemap['updated'] ? $sitemap['chunks'] : '-';
$operations = array();
//if (!empty($sitemap['context'])) {
$operations['edit'] = array(
'title' => t('Edit'),
'href' => 'admin/config/search/xmlsitemap/edit/' . $smid,
'query' => $destination,
);
//}
$operations['delete'] = array(
'title' => t('Delete'),
'href' => 'admin/config/search/xmlsitemap/delete/' . $smid,
'query' => $destination,
);
if ($operations) {
$options[$smid]['operations'] = array(
'data' => array(
'#theme' => 'links',
'#links' => $operations,
'#attributes' => array('class' => array('links', 'inline')),
),
);
}
else {
$options[$smid]['operations'] = t('None (sitemap locked)');
}
}
$form['sitemaps'] = array(
'#type' => 'tableselect',
'#header' => $header,
'#options' => $options,
'#empty' => t('No XML sitemaps available.') . ' ' . l('Add a new XML sitemap', 'admin/config/search/xmlsitemap/add'),
);
return $form;
}
function xmlsitemap_sitemap_edit_form(&$form, $form_state, array $sitemap = array()) {
$sitemap += array(
'smid' => NULL,
'context' => array(),
);
$form['#sitemap'] = $sitemap;
$form['smid'] = array(
'#type' => 'value',
'#value' => $sitemap['smid'],
);
// The context settings should be form_alter'ed by the context modules.
$form['context'] = array(
'#tree' => TRUE,
);
$form['actions'] = array(
'#type' => 'container',
'#attributes' => array('class' => array('form-actions')),
'#weight' => 100,
);
$form['actions']['save'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
$form['actions']['cancel'] = array(
'#type' => 'link',
'#href' => isset($_GET['destination']) ? $_GET['destination'] : 'admin/config/search/xmlsitemap',
'#title' => t('Cancel'),
);
// Let other modules alter this form with their context settings.
$form['#pre_render'][] = 'xmlsitemap_sitemap_edit_form_pre_render';
return $form;
}
function xmlsitemap_sitemap_edit_form_pre_render($form) {
$visible_children = element_get_visible_children($form['context']);
if (empty($visible_children)) {
$form['context']['empty'] = array(
'#type' => 'markup',
'#markup' => '<p>' . t('There are currently no XML sitemap contexts available.') . '</p>',
);
}
return $form;
}
function xmlsitemap_sitemap_edit_form_validate($form, &$form_state) {
// If there are no context options, the $form_state['values']['context']
// disappears.
$form_state['values'] += array('context' => array());
$existing = xmlsitemap_sitemap_load_by_context($form_state['values']['context']);
if ($existing && $existing['smid'] != $form_state['values']['smid']) {
form_set_error('context', t('A sitemap with the same context already exists.'));
}
}
function xmlsitemap_sitemap_edit_form_submit($form, &$form_state) {
form_state_values_clean($form_state);
xmlsitemap_sitemap_save($form_state['values']);
$uri = xmlsitemap_sitemap_uri($form_state['values']);
drupal_set_message(t('The sitemap %sitemap was saved.', array('%sitemap' => url($uri['path'], $uri['options']))));
$form_state['redirect'] = 'admin/config/search/xmlsitemap';
}
function xmlsitemap_sitemap_delete_form(&$form, $form_state, array $sitemap) {
$count = (int) db_query("SELECT COUNT(smid) FROM {xmlsitemap_sitemap}")->fetchField();
if ($count === 1 && empty($_POST)) {
drupal_set_message('It is not recommended to delete the only XML sitemap.', 'error');
}
$form['#sitemap'] = $sitemap;
$form['smid'] = array(
'#type' => 'value',
'#value' => $sitemap['smid'],
);
return confirm_form(
$form,
t('Are you sure you want to delete the sitemap?'),
'admin/config/search/xmlsitemap',
'',
t('Delete'),
t('Cancel')
);
}
function xmlsitemap_sitemap_delete_form_submit($form, $form_state) {
xmlsitemap_sitemap_delete($form_state['values']['smid']);
$uri = xmlsitemap_sitemap_uri($form['#sitemap']);
drupal_set_message(t('The sitemap %sitemap was deleted.', array('%sitemap' => url($uri['path'], $uri['options']))));
$form_state['redirect'] = 'admin/config/search/xmlsitemap';
}
/**
* Form builder; Administration settings form.
*
......@@ -33,14 +231,6 @@ function xmlsitemap_settings_form() {
'#default_value' => xmlsitemap_var('xsl'),
'#description' => t('Using the stylesheet will add formatting and tables with sorting to make it easier to view the XML sitemap data instead of viewing raw XML output. Search engines will ignore any formatting.')
);
$form['xmlsitemap']['xmlsitemap_languages'] = array(
'#type' => 'checkboxes',
'#title' => t('Generate sitemaps for the following languages'),
'#options' => array(language_default('language') => language_default('name')),
'#default_value' => xmlsitemap_var('languages'),
'#process' => array('form_process_checkboxes', '_xmlsitemap_process_language_checkboxes'),
'#description' => !module_exists('xmlsitemap_i18n') ? t('To enable multilingual features, enable the XML sitemap internationalization module.') : '',
);
$form['advanced'] = array(
'#type' => 'fieldset',
......@@ -86,10 +276,10 @@ function xmlsitemap_settings_form() {
);
$form['advanced']['xmlsitemap_base_url'] = array(
'#type' => 'textfield',
'#title' => t('Base URL'),
'#title' => t('Default base URL'),
'#default_value' => xmlsitemap_var('base_url'),
'#size' => 30,
'#description' => t('This is the base URL for links generated in the sitemap.'),
'#description' => t('This is the default base URL used for sitemaps and sitemap links.'),
'#required' => TRUE,
);
$form['advanced']['xmlsitemap_lastmod_format'] = array(
......@@ -150,23 +340,6 @@ function xmlsitemap_settings_form() {
return $form;
}
/**
* Show a link to each languages' sitemap and disable the default language
* checkbox.
*/
function _xmlsitemap_process_language_checkboxes($element) {
foreach (element_children($element) as $key) {
if ($key == language_default('language')) {
$element[$key]['#disabled'] = TRUE;
$element[$key]['#default_value'] = TRUE;
$element[$key]['#weight'] = -1;
}
$link = url('sitemap.xml', array('absolute' => TRUE, 'language' => xmlsitemap_language_load($key)));
$element[$key]['#description'] = l($link, $link);
}
return $element;
}
/**
* Form validator; Check the sitemap files directory.
*
......
......@@ -8,6 +8,7 @@ files[] = xmlsitemap.inc
files[] = xmlsitemap.admin.inc
files[] = xmlsitemap.drush.inc
files[] = xmlsitemap.generate.inc
files[] = xmlsitemap.xmlsitemap.inc
files[] = xmlsitemap.pages.inc
files[] = xmlsitemap.install
files[] = xmlsitemap.test
......
......@@ -198,6 +198,7 @@ function xmlsitemap_uninstall() {
* Implements hook_schema().
*/
function xmlsitemap_schema() {
// @todo Rename to xmlsitemap_link
$schema['xmlsitemap'] = array(
'description' => 'The base table for xmlsitemap links.',
'fields' => array(
......@@ -303,6 +304,52 @@ function xmlsitemap_schema() {
),
);
$schema['xmlsitemap_sitemap'] = array(
'fields' => array(
'smid' => array(
'description' => 'Sitemap ID',
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
),
'context_hash' => array(
'description' => 'The MD5 hash of the context field.',
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'default' => '',
),
'context' => array(
'description' => 'Serialized array with the sitemaps context',
'type' => 'text',
'not null' => TRUE,
'serialize' => TRUE,
),
'updated' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'links' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'chunks' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
),
'primary key' => array('smid'),
'unique keys' => array(
'context_hash' => array('context_hash'),
),
);
return $schema;
}
......@@ -510,7 +557,6 @@ function xmlsitemap_update_18() {
* Empty update.
*/
function xmlsitemap_update_6200() {
return array();
}
/**
......@@ -522,3 +568,57 @@ function xmlsitemap_update_7200() {
->condition('language', '')
->execute();
}
/**
* Create the {xmlsitemap_sitemap} table.
*/
function xmlsitemap_update_7201() {
if (db_table_exists('xmlsitemap_sitemap')) {
return;
}
$schema['xmlsitemap_sitemap'] = array(
'fields' => array(
'smid' => array(
'description' => 'Sitemap ID',
'type' => 'serial',
'not null' => TRUE,
),
'context_hash' => array(
'description' => 'The MD5 hash of the context field.',
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'default' => '',
),
'context' => array(
'description' => 'Serialized array with the sitemaps context',
'type' => 'text',
'not null' => TRUE,
),
'updated' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'links' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'chunks' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
),
'primary key' => array('smid'),
'unique keys' => array(
'context_hash' => array('context_hash'),
),
);
db_create_table('xmlsitemap_sitemap', $schema['xmlsitemap_sitemap']);
}
......@@ -27,6 +27,40 @@ define('XMLSITEMAP_FREQUENCY_DAILY', 86400); // 60 * 60 * 24
define('XMLSITEMAP_FREQUENCY_HOURLY', 3600); // 60 * 60
define('XMLSITEMAP_FREQUENCY_ALWAYS', 60);
/**
* Implements hook_hook_info().
*/
function xmlsitemap_hook_info() {
$hooks['xmlsitemap_link_info'] = array(
'group' => 'xmlsitemap',
);
$hooks['xmlsitemap_link_info_alter'] = array(
'group' => 'xmlsitemap',
);
$hooks['xmlsitemap_link_alter'] = array(
'group' => 'xmlsitemap',
);
$hooks['xmlsitemap_index_links'] = array(
'group' => 'xmlsitemap',
);
$hooks['xmlsitemap_context_info'] = array(
'group' => 'xmlsitemap',
);
$hooks['xmlsitemap_context'] = array(
'group' => 'xmlsitemap',
);
$hooks['xmlsitemap_context_fallback'] = array(
'group' => 'xmlsitemap',
);
$hooks['xmlsitemap_context_url_options'] = array(
'group' => 'xmlsitemap',
);
$hooks['xmlsitemap_sitemap_operations'] = array(
'group' => 'xmlsitemap',
);
return $hooks;
}
/**
* Implements hook_help().
*/
......@@ -38,8 +72,6 @@ function xmlsitemap_help($path, $arg) {
case 'admin/config/search/xmlsitemap/settings/%/%/%':
return;
case 'admin/help#xmlsitemap':
$sitemaps = xmlsitemap_get_sitemaps(TRUE);
$output .= '<p>' . format_plural(count($sitemaps), 'Your sitemap is located at !sitemap.', 'Your sitemaps are located at: !sitemaps', array('!sitemaps' => theme('item_list', array('items' => $sitemaps)), '!sitemap' => current($sitemaps))) . '</p>';
break;
case 'admin/config/search/xmlsitemap':
break;
......@@ -72,34 +104,111 @@ function xmlsitemap_permission() {
);
}
function xmlsitemap_sitemap_load($smid) {
$sitemap = db_query_range("SELECT * FROM {xmlsitemap_sitemap} WHERE smid = :smid", 0, 1, array(':smid' => $smid))->fetchAssoc();
if ($sitemap) {
$sitemap['context'] = unserialize($sitemap['context']);
}
return $sitemap;
}
function xmlsitemap_sitemap_load_by_context(array $context = NULL) {
if (!isset($context)) {
$context = xmlsitemap_get_current_context();
}
$hash = md5(serialize($context));
$smid = db_query_range("SELECT smid FROM {xmlsitemap_sitemap} WHERE context_hash = :hash", 0, 1, array(':hash' => $hash))->fetchField();
return xmlsitemap_sitemap_load($smid);
}
function xmlsitemap_sitemap_uri(array $sitemap) {
// @todo Why aren't all modules invoked sometimes? Why is this include needed?
module_load_all_includes('xmlsitemap.inc');
$uri = array();
$uri['path'] = 'sitemap.xml';
$uri['options'] = module_invoke_all('xmlsitemap_context_url_options', $sitemap['context']);
$uri['options'] += array(
'absolute' => TRUE,
'base_url' => xmlsitemap_var('base_url'),
);
return $uri;
}
function xmlsitemap_sitemap_save(array $sitemap) {
asort($sitemap['context']);
$sitemap['context_hash'] = md5(serialize($sitemap['context']));
if (!empty($sitemap['smid'])) {
drupal_write_record('xmlsitemap_sitemap', $sitemap, array('smid'));
}
else {
drupal_write_record('xmlsitemap_sitemap', $sitemap);
}
}
function xmlsitemap_sitemap_delete($smid) {
db_delete('xmlsitemap_sitemap')
->condition('smid', $smid)
->execute();
}
/**
* Implements hook_menu().
*/
function xmlsitemap_menu() {
$items['admin/config/search/xmlsitemap'] = array(
'title' => 'XML sitemap',
'description' => 'Configure the XML sitemap.',
'description' => 'Configure the XML sitemaps.',
'page callback' => 'drupal_get_form',
'page arguments' => array('xmlsitemap_settings_form'),
'page arguments' => array('xmlsitemap_sitemap_list_form'),
'access arguments' => array('administer xmlsitemap'),
'file' => 'xmlsitemap.admin.inc',
);
$items['admin/config/search/xmlsitemap/list'] = array(
'title' => 'List',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
$items['admin/config/search/xmlsitemap/add'] = array(
'title' => 'Add new XML sitemap',
'page callback' => 'drupal_get_form',
'page arguments' => array('xmlsitemap_sitemap_edit_form'),
'access arguments' => array('administer xmlsitemap'),
'type' => MENU_LOCAL_ACTION,
'file' => 'xmlsitemap.admin.inc',
);
$items['admin/config/search/xmlsitemap/edit/%xmlsitemap_sitemap'] = array(
'page callback' => 'drupal_get_form',
'page arguments' => array('xmlsitemap_sitemap_edit_form', 5),
'access arguments' => array('administer xmlsitemap'),
'type' => MENU_CALLBACK,
'file' => 'xmlsitemap.admin.inc',
);
$items['admin/config/search/xmlsitemap/delete/%xmlsitemap_sitemap'] = array(
'page callback' => 'drupal_get_form',
'page arguments' => array('xmlsitemap_sitemap_delete_form', 5),
'access arguments' => array('administer xmlsitemap'),
'type' => MENU_CALLBACK,
'file' => 'xmlsitemap.admin.inc',
);
$items['admin/config/search/xmlsitemap/settings'] = array(
'title' => 'Settings',
'page callback' => 'drupal_get_form',
'page arguments' => array('xmlsitemap_settings_form'),
'access arguments' => array('administer xmlsitemap'),
'type' => MENU_DEFAULT_LOCAL_TASK,
'type' => MENU_LOCAL_TASK,
'file' => 'xmlsitemap.admin.inc',
'weight' => -10,
'weight' => 10,
);
$items['admin/config/search/xmlsitemap/rebuild'] = array(
'title' => 'Rebuild',
'title' => 'Rebuild links',
'description' => 'Rebuild the site map.',
'page callback' => 'drupal_get_form',
'page arguments' => array('xmlsitemap_rebuild_form'),
'access arguments' => array('administer xmlsitemap'),
'type' => MENU_LOCAL_TASK,
'file' => 'xmlsitemap.admin.inc',
'weight' => 10,
'weight' => 20,
);
$items['sitemap.xml'] = array(
......@@ -149,77 +258,17 @@ function xmlsitemap_cron() {
xmlsitemap_regenerate();
}
/**
* Implements hook_xmlsitemap_links().
*/
function xmlsitemap_xmlsitemap_links() {
// Frontpage link.
$links[] = array(
'type' => 'frontpage',
'id' => 0,
'loc' => '',
);
return $links;
}
/**
* Implements hook_xmlsitemap_link_alter().
*/
function xmlsitemap_xmlsitemap_link_alter(&$link) {
// Alter the frontpage priority.
if ($link['type'] == 'frontpage' || $link['loc'] == '' || $link['loc'] == variable_get('site_frontpage', 'node')) {
$link['priority'] = xmlsitemap_var('frontpage_priority');
$link['changefreq'] = xmlsitemap_var('frontpage_changefreq');
}
}
/**
* Implements hook_robotstxt().
*/
function xmlsitemap_robotstxt() {
$sitemaps = xmlsitemap_get_sitemaps();
foreach ($sitemaps as $index => $sitemap) {
$sitemaps[$index] = 'Sitemap: ' . $sitemap;
// @todo Simplify this down to one function somehow?
$context = xmlsitemap_get_current_context();
if ($sitemap = xmlsitemap_sitemap_load_by_context($context)) {
$uri = xmlsitemap_sitemap_uri($sitemap);
$robotstxt[] = 'Sitemap: ' . url($uri['path'], $uri['options']);
return $robotstxt;
}
return $sitemaps;
}
/**
* Get an array of the current site's sitemaps.
*
* @param $links
* A boolean if TRUE, the array elements will be HTML links.
* @return
* An array of sitemaps.
*/
function xmlsitemap_get_sitemaps($links = FALSE) {
static $sitemaps = array();
if (!$sitemaps) {
$url_options = xmlsitemap_get_url_options();
$sitemap_languages = xmlsitemap_var('languages');
natsort($sitemap_languages);
foreach ($sitemap_languages as $language) {
$url_options['language'] = xmlsitemap_language_load($language);
$sitemap = url('sitemap.xml', $url_options);
$sitemaps[$language] = $links ? l($sitemap, $sitemap) : $sitemap;
}
}
return $sitemaps;