diff --git a/xmlsitemap.admin.inc b/xmlsitemap.admin.inc
index 496dd2c..e21bbfc 100644
--- a/xmlsitemap.admin.inc
+++ b/xmlsitemap.admin.inc
@@ -354,6 +354,12 @@ function xmlsitemap_settings_form($form, &$form_state) {
'#default_value' => variable_get('xmlsitemap_disable_cron_regeneration', 0),
'#description' => t('This can be disabled if other methods are being used to generate the sitemap files, like drush xmlsitemap-regenerate.'),
);
+ $form['advanced']['xmlsitemap_language_fallback'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Include links to untranslated entities to localized sitemaps'),
+ '#description' => t('If the option disabled, it will not include links to localized sitemaps even the language fallback enabled.'),
+ '#default_value' => variable_get('xmlsitemap_language_fallback', TRUE),
+ );
$form['advanced']['xmlsitemap_output_elements'] = array(
'#type' => 'checkboxes',
'#title' => t('Enable or disable the individual @loc elements from output', array('@loc' => '')),
diff --git a/xmlsitemap.install b/xmlsitemap.install
index 916ebec..44ef8d2 100644
--- a/xmlsitemap.install
+++ b/xmlsitemap.install
@@ -239,7 +239,7 @@ function xmlsitemap_schema() {
'default' => 0,
),
),
- 'primary key' => array('id', 'type'),
+ 'primary key' => array('id', 'type', 'language'),
'indexes' => array(
'loc' => array('loc'),
'access_status_loc' => array('access', 'status', 'loc'),
@@ -568,3 +568,11 @@ function _xmlsitemap_sitemap_rehash_all() {
}
}
}
+
+/**
+ * Add new primary key including the language.
+ */
+function xmlsitemap_update_7204() {
+ db_drop_primary_key('xmlsitemap');
+ db_add_primary_key('xmlsitemap', array('id', 'type', 'language'));
+}
diff --git a/xmlsitemap.module b/xmlsitemap.module
index 09d02ea..e70f8fc 100644
--- a/xmlsitemap.module
+++ b/xmlsitemap.module
@@ -603,7 +603,17 @@ function xmlsitemap_link_save(array $link, array $context = array()) {
$link['changecount'] = 0;
}
- $existing = db_query_range("SELECT loc, access, status, lastmod, priority, changefreq, changecount, language FROM {xmlsitemap} WHERE type = :type AND id = :id", 0, 1, array(':type' => $link['type'], ':id' => $link['id']))->fetchAssoc();
+ $link_keys = array('type', 'id');
+
+ // If entity translation exists and the link has a language we need to add the
+ // language to the query to fetch the unique / language specific link.
+ if (module_exists('entity_translation') && entity_get_info($link['type']) && entity_translation_enabled($link['type']) && !empty($link['language'])) {
+ $existing = db_query_range("SELECT loc, access, status, lastmod, priority, changefreq, changecount, language FROM {xmlsitemap} WHERE type = :type AND id = :id AND language = :language", 0, 1, array(':type' => $link['type'], ':id' => $link['id'], ':language' => $link['language']))->fetchAssoc();
+ $link_keys[] = 'language';
+ }
+ else {
+ $existing = db_query_range("SELECT loc, access, status, lastmod, priority, changefreq, changecount, language FROM {xmlsitemap} WHERE type = :type AND id = :id", 0, 1, array(':type' => $link['type'], ':id' => $link['id']))->fetchAssoc();
+ }
// Check if this is a changed link and set the regenerate flag if necessary.
if (!variable_get('xmlsitemap_regenerate_needed', FALSE)) {
@@ -612,7 +622,7 @@ function xmlsitemap_link_save(array $link, array $context = array()) {
// Save the link and allow other modules to respond to the link being saved.
if ($existing) {
- drupal_write_record('xmlsitemap', $link, array('type', 'id'));
+ drupal_write_record('xmlsitemap', $link, $link_keys);
module_invoke_all('xmlsitemap_link_update', $link, $context);
}
else {
@@ -663,11 +673,17 @@ function xmlsitemap_link_update_multiple($updates = array(), $conditions = array
* A string with the entity type.
* @param $entity_id
* An integer with the entity ID.
+ * @param $langcode
+ * An optional language code for the link that should be deleted.
+ * If omitted, links for that entity will be removed in all languages.
* @return
* The number of links that were deleted.
*/
-function xmlsitemap_link_delete($entity_type, $entity_id) {
+function xmlsitemap_link_delete($entity_type, $entity_id, $langcode = NULL) {
$conditions = array('type' => $entity_type, 'id' => $entity_id);
+ if ($langcode) {
+ $conditions['language'] = $langcode;
+ }
return xmlsitemap_link_delete_multiple($conditions);
}
@@ -1151,6 +1167,14 @@ function xmlsitemap_field_attach_delete_bundle($entity_type, $bundle, $instances
}
/**
+ * Implements hook_entity_translation_delete().
+ */
+function xmlsitemap_entity_translation_delete($entity_type, $entity, $langcode) {
+ list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
+ xmlsitemap_link_delete($entity_type, $id, $langcode);
+}
+
+/**
* Determine the frequency of updates to a link.
*
* @param $interval
@@ -1593,3 +1617,45 @@ function xmlsitemap_link_enqueue($type, $ids) {
$queue = DrupalQueue::get('xmlsitemap_link_process');
$queue->createItem($data);
}
+
+/**
+ * Determines the languages to process for an entity.
+ *
+ * If entity_translation is available the languages are determined by using the
+ * translation handler, otherwise it falls back to the default language.
+ *
+ * @param string $entity_type
+ * The type of entity.
+ * @param object $entity
+ * The entity.
+ * @param string $default_language
+ * Set the default language to use if no translations / entity languages where
+ * found.
+ *
+ * @return array
+ * Array with the language codes of available languages.
+ * Returns only languages of published translations. If entity isn't handled
+ * by entity translation the default language is used.
+ */
+function xmlsitemap_get_entity_languages($entity_type, $entity, $default_language = LANGUAGE_NONE) {
+ if (module_exists('entity_translation')) {
+ if (entity_translation_enabled($entity_type, $entity)) {
+ $handler = entity_translation_get_handler($entity_type, $entity);
+ if (!empty($handler)) {
+ $languages = array();
+ $translations = $handler->getTranslations();
+ foreach ($translations->data as $translation_lang => $translation_data) {
+ $languages[$translation_lang] = (int) $translation_data['status'];
+ }
+ // Detect allowing fallback for languages for entities not yet translated.
+ $fallback = (int) (variable_get('locale_field_language_fallback', TRUE) && variable_get('xmlsitemap_language_fallback', TRUE));
+ // Retrieve all active languages in the site.
+ $available_languages = locale_language_list('language');
+ // Add languages for entities not yet translated.
+ $languages += array_fill_keys(array_diff_key($available_languages, $languages), $fallback);
+ return $languages;
+ }
+ }
+ }
+ return array($default_language);
+}
diff --git a/xmlsitemap_i18n/xmlsitemap_i18n.install b/xmlsitemap_i18n/xmlsitemap_i18n.install
new file mode 100644
index 0000000..1eddcd7
--- /dev/null
+++ b/xmlsitemap_i18n/xmlsitemap_i18n.install
@@ -0,0 +1,63 @@
+condition('context', serialize($context))
+ ->execute();
+
+ // Add a sitemap for each language.
+ foreach ($languages as $language) {
+ $context = array('language' => $language);
+ db_insert('xmlsitemap_sitemap')
+ ->fields(array(
+ 'smid' => xmlsitemap_sitemap_get_context_hash($context),
+ 'context' => serialize($context),
+ ))
+ ->execute();
+ }
+ }
+}
+
+/**
+ * Implements hook_uninstall().
+ *
+ * Delete sitemaps related to languages and set 1 default sitemap.
+ */
+function xmlsitemap_i18n_uninstall() {
+ if (module_exists('locale') && ($languages = array_keys(locale_language_list()))) {
+ // Delete sitemap for each language.
+ foreach ($languages as $language) {
+ $context = array('language' => $language);
+ db_delete('xmlsitemap_sitemap')
+ ->condition('context', serialize($context))
+ ->execute();
+ }
+
+ // Add default sitemap.
+ db_insert('xmlsitemap_sitemap')
+ ->fields(array(
+ 'smid' => xmlsitemap_sitemap_get_context_hash($context),
+ 'context' => serialize($context),
+ ))
+ ->execute();
+ }
+}
diff --git a/xmlsitemap_node/xmlsitemap_node.module b/xmlsitemap_node/xmlsitemap_node.module
index 20f5f05..e7c8035 100644
--- a/xmlsitemap_node/xmlsitemap_node.module
+++ b/xmlsitemap_node/xmlsitemap_node.module
@@ -39,8 +39,7 @@ function xmlsitemap_node_xmlsitemap_index_links($limit) {
function xmlsitemap_node_xmlsitemap_process_node_links(array $nids) {
$nodes = node_load_multiple($nids);
foreach ($nodes as $node) {
- $link = xmlsitemap_node_create_link($node);
- xmlsitemap_link_save($link, array($link['type'] => $node));
+ xmlsitemap_node_node_update($node);
}
}
@@ -56,7 +55,18 @@ function xmlsitemap_node_node_insert(stdClass $node) {
*/
function xmlsitemap_node_node_update(stdClass $node) {
$link = xmlsitemap_node_create_link($node);
- xmlsitemap_link_save($link, array($link['type'] => $node));
+ if (!empty($link['languages'])) {
+ $link_status = (int) $link['status'];
+ foreach ($link['languages'] as $lang => $lang_status) {
+ $lang_link = $link;
+ $lang_link['language'] = $lang;
+ $lang_link['status'] = (int) ($link_status && $lang_status);
+ xmlsitemap_link_save($lang_link, array($link['type'] => $node));
+ }
+ }
+ else {
+ xmlsitemap_link_save($link, array($link['type'] => $node));
+ }
}
/**
@@ -204,7 +214,10 @@ function xmlsitemap_node_create_link(stdClass $node) {
$node->xmlsitemap['loc'] = $uri['path'];
$node->xmlsitemap['lastmod'] = count($timestamps) ? max($timestamps) : 0;
$node->xmlsitemap['access'] = $node->nid ? xmlsitemap_node_view_access($node, drupal_anonymous_user()) : 1;
- $node->xmlsitemap['language'] = isset($node->language) ? $node->language : LANGUAGE_NONE;
+ // Fetches the languages for the sitemap link / links.
+ $language = isset($node->language) ? $node->language : LANGUAGE_NONE;
+ $node->xmlsitemap['language'] = $language;
+ $node->xmlsitemap['languages'] = xmlsitemap_get_entity_languages('node', $node, $language);
return $node->xmlsitemap;
}
diff --git a/xmlsitemap_taxonomy/xmlsitemap_taxonomy.module b/xmlsitemap_taxonomy/xmlsitemap_taxonomy.module
index f0d335d..8baaa61 100644
--- a/xmlsitemap_taxonomy/xmlsitemap_taxonomy.module
+++ b/xmlsitemap_taxonomy/xmlsitemap_taxonomy.module
@@ -49,8 +49,7 @@ function xmlsitemap_taxonomy_xmlsitemap_index_links($limit) {
function xmlsitemap_taxonomy_xmlsitemap_process_taxonomy_term_links(array $tids) {
$terms = taxonomy_term_load_multiple($tids);
foreach ($terms as $term) {
- $link = xmlsitemap_taxonomy_create_link($term);
- xmlsitemap_link_save($link, array($link['type'] => $term));
+ xmlsitemap_taxonomy_term_update($term);
}
}
@@ -106,8 +105,7 @@ function xmlsitemap_taxonomy_vocabulary_update(stdClass $vocabulary) {
* Implements hook_taxonomy_term_insert() {
*/
function xmlsitemap_taxonomy_term_insert(stdClass $term) {
- $link = xmlsitemap_taxonomy_create_link($term);
- xmlsitemap_link_save($link, array($link['type'] => $term));
+ xmlsitemap_taxonomy_term_update($term);
}
/**
@@ -115,7 +113,18 @@ function xmlsitemap_taxonomy_term_insert(stdClass $term) {
*/
function xmlsitemap_taxonomy_term_update(stdClass $term) {
$link = xmlsitemap_taxonomy_create_link($term);
- xmlsitemap_link_save($link, array($link['type'] => $term));
+ if (!empty($link['languages'])) {
+ $link_status = (int) $link['status'];
+ foreach ($link['languages'] as $lang => $lang_status) {
+ $lang_link = $link;
+ $lang_link['language'] = $lang;
+ $lang_link['status'] = (int) ($link_status && $lang_status);
+ xmlsitemap_link_save($lang_link, array($link['type'] => $term));
+ }
+ }
+ else {
+ xmlsitemap_link_save($link, array($link['type'] => $term));
+ }
}
/**
@@ -175,7 +184,10 @@ function xmlsitemap_taxonomy_create_link(stdClass &$term) {
// @todo How can/should we check taxonomy term access?
$term->xmlsitemap['loc'] = $uri['path'];
$term->xmlsitemap['access'] = 1;
- $term->xmlsitemap['language'] = isset($term->language) ? $term->language : LANGUAGE_NONE;
+ // Fetches the languages for the sitemap link / links.
+ $language = isset($term->language) ? $term->language : LANGUAGE_NONE;
+ $term->xmlsitemap['language'] = $language;
+ $term->xmlsitemap['languages'] = xmlsitemap_get_entity_languages('taxonomy_term', $term, $language);
return $term->xmlsitemap;
}