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..705fc4b 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,19 @@ 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'])) { + $bundle_info = xmlsitemap_link_bundle_load('node', $node->type); + $link_status = (int) $bundle_info['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 +215,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..9bdab3f 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,19 @@ 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'])) { + $bundle_info = xmlsitemap_link_bundle_load('taxonomy_term', $term->vocabulary_machine_name); + $link_status = (int) $bundle_info['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 +185,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; }