fetchField() > 0) { db_query("RENAME TABLE {metatag} TO {metatag}_legacy"); $message = 'An out-of-date version of the {metatag} table was discovered. As the table contained data it was renamed with a suffix of "_legacy". This will not prevent installation from continuing, but will need to be dealt with later. See https://www.drupal.org/node/1391554 for further details.'; } // The table is empty, so delete it. else { db_query("DROP TABLE {metatag}"); $message = 'An out-of-date version of the {metatag} table was discovered. As the table was empty it was simply removed so that it could be recreated in the correct format. Installation may now proceed. See https://www.drupal.org/node/1391554 for further details.'; } $requirements['metatag'] = array( 'severity' => REQUIREMENT_WARNING, 'title' => 'Metatag', 'value' => $t('Legacy data discovered.'), 'description' => $t($message), ); drupal_set_message($t($message), 'warning'); break; } } } } } elseif ($phase == 'runtime') { // Work out the release of D7 that is currently running. list($major, $minor) = explode('.', VERSION); // Strip off any suffixes on the version string, e.g. "17-dev". if (strpos('-', $minor)) { list($minor, $suffix) = explode('-', $minor); } // Releases of Drupal older than 7.28 did not have entity_language(), which // is now required, and had a broken [node:summary] token. if ($minor < 28) { $requirements['metatag'] = array( 'severity' => REQUIREMENT_WARNING, 'title' => 'Metatag', 'value' => $t('Upgrade Drupal core to v7.28 or newer'), 'description' => $t("This older version of Drupal core is missing functionality necessary for the module's multilingual support and contains a broken [node:summary] token, it must be upgraded to version 7.28 or newer."), ); } // Everything's OK. else { $requirements['metatag'] = array( 'severity' => REQUIREMENT_OK, 'title' => 'Metatag', 'value' => $t('Drupal core is compatible'), 'description' => $t('Older versions of Drupal core contained bugs that made them incompatible with Metatag, but this version will work correctly.'), ); } // Add a note if Page Title is also installed. if (module_exists('page_title')) { $requirements['metatag_page_title'] = array( 'severity' => REQUIREMENT_INFO, 'title' => 'Metatag', 'value' => $t('Possible conflicts with Page Title module'), 'description' => $t('The Metatag module is able to customize page titles so running the Page Title module simultaneously can lead to complications.'), ); } // Add a note if the deprecated metatag.entity_translation.inc file still // exists. $filename = 'metatag.entity_translation.inc'; if (file_exists(dirname(__FILE__) . '/' . $filename)) { $requirements['metatag_deprecated_et_file'] = array( 'severity' => REQUIREMENT_ERROR, 'title' => 'Metatag', 'value' => $t('Unwanted :filename file found', array(':filename' => $filename)), 'description' => $t("The :filename file was removed in v7.x-1.0-beta5 but it still exists in the site's Metatag module's directory and will cause problems. This file needs to be removed. The file's path in the Drupal directory structure is:
!short_path
The file's full path is:
!full_path", array(':filename' => $filename, '!short_path' => drupal_get_path('module', 'metatag') . '/' . $filename, '!full_path' => dirname(__FILE__) . $filename)), ); } // Check that Entity_Translation is current. if (module_exists('entity_translation')) { $rev = db_query("SELECT schema_version FROM {system} WHERE name = :module", array(':module' => 'entity_translation'))->fetchColumn(); if ($rev < 7004) { $requirements['metatag_et_old'] = array( 'severity' => REQUIREMENT_ERROR, 'title' => 'Metatag', 'value' => $t('Entity_Translation is out of date and requires updating', array('@url' => 'http://drupal.org/project/entity_translation')), 'description' => $t('The Entity_Translation module is out of date and needs to be updated in order to be compatible with Metatag.'), ); } } // It's recommended to install the Transliteration module to clean up file // paths for use with image meta tags. if (!module_exists('transliteration')) { $requirements['metatag_transliteration'] = array( 'severity' => REQUIREMENT_INFO, 'title' => 'Metatag', 'value' => $t('The Transliteration module is recommended.'), 'description' => $t("It is recommended to install the Transliteration module to clean up filenames of uploaded files that may be used with image meta tags.", array('@url' => 'https://drupal.org/project/transliteration')), ); } // It's recommended to install the Imagecache Token module to make image // tokens easier to do. if (!module_exists('imagecache_token')) { $requirements['metatag_imagecache_token'] = array( 'severity' => REQUIREMENT_INFO, 'title' => 'Metatag', 'value' => $t('The Imagecache Token module is recommended.'), 'description' => $t("It is recommended to install the Imagecache Token module to make it easier to control image meta tags, e.g. og:image.", array('@url' => 'https://drupal.org/project/imagecache_token')), ); } // The Admin Language module can cause problems. if (!module_exists('admin_language') && variable_get('admin_language_force_neutral', 0)) { $requirements['metatag_admin_language'] = array( 'severity' => REQUIREMENT_WARNING, 'title' => 'Metatag', 'value' => $t('Conflict with Admin Language module.'), 'description' => $t("Using the \"@option\" with Metatag can lead to data loss, so it is recommended to disable that option.", array('@option' => t('Force language neutral aliases'), '@url' => url('admin/config/regional/language/admin_language'))), ); } } return $requirements; } /** * Implements hook_schema(). */ function metatag_schema() { $schema['metatag_config'] = array( 'description' => 'Storage of meta tag configuration and defaults.', 'export' => array( 'key' => 'instance', 'key name' => 'Instance', 'primary key' => 'cid', 'identifier' => 'config', 'default hook' => 'metatag_config_default', 'api' => array( 'owner' => 'metatag', 'api' => 'metatag', 'minimum_version' => 1, 'current_version' => 1, ), 'cache defaults' => TRUE, 'default cache bin' => 'cache_metatag', ), 'fields' => array( 'cid' => array( 'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE, 'description' => 'The primary identifier for a metatag configuration set.', 'no export' => TRUE, ), 'instance' => array( 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '', 'description' => 'The machine-name of the configuration, typically entity-type:bundle.', ), 'config' => array( 'type' => 'blob', 'size' => 'big', 'not null' => TRUE, 'serialize' => TRUE, 'description' => 'Serialized data containing the meta tag configuration.', 'translatable' => TRUE, ), ), 'primary key' => array('cid'), 'unique keys' => array( 'instance' => array('instance'), ), ); $schema['metatag'] = array( 'fields' => array( 'entity_type' => array( 'type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => '', 'description' => 'The entity type this data is attached to.', ), 'entity_id' => array( 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, 'description' => 'The entity id this data is attached to.', ), 'revision_id' => array( 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, 'description' => 'The revision_id for the entity object this data is attached to.', ), 'language' => array( 'type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => '', 'description' => 'The language of the tag.', ), 'data' => array( 'type' => 'blob', 'size' => 'big', 'not null' => TRUE, 'serialize' => TRUE, ), ), 'indexes' => array( 'type_revision' => array('entity_type','revision_id'), ), 'primary key' => array('entity_type', 'entity_id', 'revision_id', 'language'), ); $schema['cache_metatag'] = drupal_get_schema_unprocessed('system', 'cache'); $schema['cache_metatag']['description'] = t('Cache table for the generated meta tag output.'); return $schema; } /** * Implements hook_install(). */ function metatag_install() { drupal_set_message(t("Thank you for installing the Metatag module. It is recommended to read the module's README.txt file as there are some known issues that may affect this site.", array('!url' => url(drupal_get_path('module', 'metatag') . '/README.txt')))); } /** * Implements hook_uninstall(). */ function metatag_uninstall() { // This variable is created via hook_enable. variable_del('metatag_schema_installed'); // Used to control whether 403/404 pages are cached. variable_del('metatag_cache_error_pages'); // Used to make meta tags display on admin pages. variable_del('metatag_tag_admin_pages'); // Temp variables, just in case they weren't removed already. variable_del('metatag_skip_update_7017'); // Used to note that the schema for the main {metatag} table were sufficiently // updated. variable_del('metatag_has_revision_id'); // Used to force an entity's default language values to be used if nothing // else matched. variable_del('metatag_entity_no_lang_default'); } /** * Implements hook_enable(). */ function metatag_enable() { variable_set('metatag_schema_installed', TRUE); } /** * Implements hook_disable(). */ // function metatag_disable() { // } /** * Disable the deprecated metatag_ui module which has been merged into metatag. */ function metatag_update_7000() { if (module_exists('metatag_ui')) { module_disable(array('metatag_ui'), FALSE); drupal_uninstall_modules(array('metatag_ui'), FALSE); } } /** * Fix the "{metatag_config}.cid column cannot be NULL" error. */ function metatag_update_7001() { $table_name = 'metatag_config'; $field_name = 'cid'; $field_spec = array( 'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE, 'description' => 'The primary identifier for a metatag configuration set.', ); $keys = array('primary key' => array($field_name)); // Before making any changes, drop the existing primary key. // Let's add a temporary unique key for cid so MySQL will let it go. // Hint taken from https://drupal.org/node/2064305#comment-7753197. db_add_unique_key($table_name, 'temp_key', array($field_name, 'instance')); // Unforunately there is no API way to check if a primary key exists, so if // it doesn't exist the db_drop_primary_key() call will fail. try { db_drop_primary_key($table_name); } catch (Exception $e) { drupal_set_message('Caught an exception: ', $e->getMessage()); } // Rejig the field, and turn on the primary key again. db_change_field($table_name, $field_name, $field_name, $field_spec, $keys); // Finally, remove the temporary unique key because it's no longer useful. db_drop_unique_key($table_name, 'temp_key'); } /** * Disable the deprecated metatag_ui module which has been merged into metatag, * again. */ function metatag_update_7002() { if (module_exists('metatag_ui')) { module_disable(array('metatag_ui'), FALSE); drupal_uninstall_modules(array('metatag_ui'), FALSE); drupal_set_message(t('The deprecated Metatag UI module has been disabled.')); } } /** * Add the {metatag}.language field. */ function metatag_update_7003() { // Set the target table and field name. $table_name = 'metatag'; $field_name = 'language'; // Don't add the new field if it already exists. if (!db_field_exists($table_name, $field_name)) { // Describe the new field. $field_spec = array( 'type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => '', 'description' => 'The language of the tag', ); // Add it and update the primary key. db_add_field($table_name, $field_name, $field_spec); db_drop_primary_key($table_name); db_add_primary_key($table_name, array('entity_type', 'entity_id', 'language')); } } /** * Replaced by updates 7009, 7010, 7011, 7012 and 7013. */ function metatag_update_7004() { // Do nothing. } /** * Removing wrong metatag watchdog entries that break the admin/reports/dblog * page. */ function metatag_update_7005() { if (db_table_exists('watchdog')) { db_delete('watchdog') ->condition('type', 'metatag') ->condition('variables', serialize('info')) ->execute(); } } /** * Remove {metatag} records that were added by old versions of the module for * entities that don't actually support Metatag. A more complete version of * this will be added later on after it's (hopefully) guaranteed that all * modules have updated to the correct API usage. */ function metatag_update_7006() { $entity_types = array( // Core. 'comment', 'menu_link', 'taxonomy_vocabulary', // Some contrib entities. 'mailchimp_list', 'profile2', 'profile2_type', 'redirect', 'rules_config', 'wysiwyg_profile', ); foreach ($entity_types as $entity_type) { $num_deleted = db_delete('metatag') ->condition('entity_type', $entity_type) ->execute(); if ($num_deleted > 0) { drupal_set_message(t('Removed @count meta tag record(s) for the @type entity type, it does not support meta tags.', array('@count' => $num_deleted, '@type' => $entity_type))); } } } /** * Remove {metatag} records for nodes, users and taxonomy terms that have been * deleted; older versions of Metatag may have failed to purge these. */ function metatag_update_7007() { $nodes = db_query("SELECT m.entity_id FROM {metatag} m LEFT OUTER JOIN {node} n ON m.entity_id=n.nid WHERE m.entity_type='node' AND n.nid IS NULL") ->fetchCol(); if (count($nodes) > 0) { $deleted = db_delete('metatag') ->condition('entity_type', 'node') ->condition('entity_id', $nodes) ->execute(); if ($deleted > 0) { drupal_set_message(t('Removed @count meta tag record(s) for nodes that had been purged.', array('@count' => $deleted))); } else { drupal_set_message(t('There were no meta tag records to purge for removed nodes. This is a good thing :)')); } } $users = db_query("SELECT m.entity_id FROM {metatag} m LEFT OUTER JOIN {users} u ON m.entity_id=u.uid WHERE m.entity_type='user' AND u.uid IS NULL") ->fetchCol(); if (count($users) > 0) { $deleted = db_delete('metatag') ->condition('entity_type', 'user') ->condition('entity_id', $users) ->execute(); if ($deleted > 0) { drupal_set_message(t('Removed @count meta tag record(s) for users that had been purged.', array('@count' => $deleted))); } else { drupal_set_message(t('There were no meta tag records to purge for removed users. This is a good thing :)')); } } // Only run this if the Taxonomy module is enabled. if (module_exists('taxonomy')) { $terms = db_query("SELECT m.entity_id FROM {metatag} m LEFT OUTER JOIN {taxonomy_term_data} t ON m.entity_id=t.tid WHERE m.entity_type='taxonomy_term' AND t.tid IS NULL") ->fetchCol(); if (count($terms) > 0) { $deleted = db_delete('metatag') ->condition('entity_type', 'taxonomy_term') ->condition('entity_id', $terms) ->execute(); if ($deleted > 0) { drupal_set_message(t('Removed @count meta tag record(s) for taxonomy terms that had been purged.', array('@count' => $deleted))); } else { drupal_set_message(t('There were no meta tag records to purge for removed taxonomy terms. This is a good thing :)')); } } } } /** * Remove any empty records that may be hanging around from old releases. */ function metatag_update_7008() { $conditions = db_or() ->isNull('data') ->condition('data', '') ->condition('data', serialize(array())); $deleted = db_delete("metatag") ->condition($conditions) ->execute(); if ($deleted > 0) { drupal_set_message(t('Purged @count empty meta tag record(s).', array('@count' => $deleted))); } } /** * Fix {metatag} records for taxonomy terms. */ function metatag_update_7009() { if (module_exists('taxonomy')) { // Fix the {metatag} table first. metatag_update_7015(); // Remove duplicates. _metatag_remove_dupes('taxonomy_term'); } // The taxonomy term entity doesn't support a 'language' option, so reset it // to LANGUAGE_NONE. $result = db_query("UPDATE {metatag} SET language = :language WHERE entity_type='taxonomy_term'", array(':language' => LANGUAGE_NONE)); if ($result->rowCount() > 0) { drupal_set_message(t('Fixed language values for @count taxonomy terms.', array('@count' => $result->rowCount()))); } } /** * Fix {metatag} records for users. */ function metatag_update_7010() { // Fix the {metatag} table first. metatag_update_7015(); // Remove duplicates. _metatag_remove_dupes('user'); // Update User values. $result = db_query("UPDATE {metatag} SET language = :language WHERE entity_type='user'", array(':language' => LANGUAGE_NONE)); if ($result->rowCount() > 0) { drupal_set_message(t('Fixed language values for @count user records.', array('@count' => $result->rowCount()))); } } /** * Fix {metatag} records for nodes. */ function metatag_update_7011(&$sandbox) { // Fix the {metatag} table first. metatag_update_7015(); // Only proceed if Entity_Translation is not enabled as it allows each node // record to have multiple languages available. if (module_exists('entity_translation')) { drupal_set_message(t("Entity Translation is enabled, so node meta tags will not be updated, to avoid accidental dataloss.")); return; } // Process records by groups of 10 (arbitrary value). // When a group is processed, the batch update engine determines whether it // should continue processing in the same request or provide progress // feedback to the user and wait for the next request. $limit = 10; // When ran through Drush it's Ok to process a larger number of objects at a // time. if (drupal_is_cli()) { $limit = 100; } // Use the sandbox at your convenience to store the information needed // to track progression between successive calls to the function. if (!isset($sandbox['progress'])) { // The count of records visited so far. $sandbox['progress'] = 0; // Remove duplicates. _metatag_remove_dupes('node'); // Update Node values. $nodes = db_query("SELECT n.nid, n.language FROM {node} n INNER JOIN {metatag} m ON n.nid = m.entity_id WHERE m.entity_type = 'node' AND n.language != m.language ORDER BY nid"); $sandbox['records'] = array(); foreach ($nodes as $record) { $sandbox['records'][] = $record; } // If there's no data, don't bother with the extra work. if (empty($sandbox['records'])) { watchdog('metatag', 'Update 7011: No nodes need the Metatag language values fixed.', array(), WATCHDOG_INFO); if (drupal_is_cli()) { drupal_set_message(t('Update 7011: No nodes need the Metatag language values fixed.')); } return t('No nodes need the Metatag language values fixed.'); } // Total records that must be visited. $sandbox['max'] = count($sandbox['records']); // A place to store messages during the run. $sandbox['messages'] = array(); // An initial record of the number of records to be updated. watchdog('metatag', 'Update 7011: !count records to update.', array('!count' => $sandbox['max']), WATCHDOG_INFO); if (drupal_is_cli()) { drupal_set_message(t('Update 7011: !count records to update.', array('!count' => $sandbox['max']))); } // Last record processed. $sandbox['current_record'] = -1; // Because a lot of other processing happens on the first iteration, just do // one. $limit = 1; } // Set default values. for ($ctr = 0; $ctr < $limit; $ctr++) { $sandbox['current_record']++; if (empty($sandbox['records'][$sandbox['current_record']])) { break; } // Shortcuts for later. $langcode = $sandbox['records'][$sandbox['current_record']]->language; $nid = $sandbox['records'][$sandbox['current_record']]->nid; db_update('metatag') ->fields(array('language' => $langcode)) ->condition('entity_type', 'node') ->condition('entity_id', $nid) ->execute(); // Update our progress information. $sandbox['progress']++; } // Set the "finished" status, to tell batch engine whether this function // needs to run again. If you set a float, this will indicate the progress of // the batch so the progress bar will update. $sandbox['#finished'] = ($sandbox['progress'] >= $sandbox['max']) ? TRUE : ($sandbox['progress'] / $sandbox['max']); if ($sandbox['#finished']) { // Clear all caches so the fixed data will be reloaded. cache_clear_all('*', 'cache_metatag', TRUE); // A final log of the number of records that were converted. watchdog('metatag', 'Update 7011: !count records were updated in total.', array('!count' => $sandbox['progress']), WATCHDOG_INFO); if (drupal_is_cli()) { drupal_set_message(t('Update 7011: !count records were updated.', array('!count' => $sandbox['progress']))); } // hook_update_N() may optionally return a string which will be displayed // to the user. return t('Fixed the Metatag language values for @count nodes.', array('!count' => $sandbox['progress'])); } } /** * Remove duplicate {metatag} records for non-core entities. */ function metatag_update_7012() { // Fix the {metatag} table first. metatag_update_7015(); if (module_exists('entity_translation')) { drupal_set_message(t("Entity Translation is enabled, duplicate meta tags will not be removed for custom entities, to avoid accidental dataloss.")); return; } $records = db_select('metatag', 'm') ->fields('m', array('entity_type')) ->condition('m.entity_type', array('node', 'taxonomy_term', 'user'), 'NOT IN') ->orderBy('m.entity_type', 'ASC') ->orderBy('m.entity_id', 'ASC') ->distinct() ->execute(); $entity_types = array(); foreach ($records as $record) { $entity_types[] = $record->entity_type; // Remove duplicates. _metatag_remove_dupes($record->entity_type); } if (empty($entity_types)) { drupal_set_message(t('There were no other records to fix.')); } } /** * Fix the {metatag} language value for all non-core entity records. This might * take a while, depending on how much data needs to be converted. */ function metatag_update_7013(&$sandbox) { // Fix the {metatag} table first. metatag_update_7015(); if (module_exists('entity_translation')) { drupal_set_message(t("Entity Translation is enabled, meta tags will not be updated for custom entities, to avoid accidental dataloss.")); return; } // Use the sandbox at your convenience to store the information needed // to track progression between successive calls to the function. if (!isset($sandbox['progress'])) { // The count of records visited so far. $sandbox['progress'] = 0; // Because the {metatag} table uses multiple primary keys, there's no easy // way to do this, so we're going to cache all record keys and manually // step through them. $records = db_select('metatag', 'm') ->fields('m', array('entity_type', 'entity_id')) ->condition('m.entity_type', array('node', 'taxonomy_term', 'user'), 'NOT IN') ->orderBy('m.entity_type', 'ASC') ->orderBy('m.entity_id', 'ASC') ->execute(); $sandbox['records'] = array(); foreach ($records as $record) { $sandbox['records'][] = $record; } // If there's no data, don't bother with the extra work. if (empty($sandbox['records'])) { watchdog('metatag', 'Update 7013: No meta tag records need updating.', array(), WATCHDOG_INFO); if (drupal_is_cli()) { drupal_set_message(t('Update 7013: No meta tag records need updating.')); } return t('No meta tag records need updating.'); } // Total records that must be visited. $sandbox['max'] = count($sandbox['records']); // A place to store messages during the run. $sandbox['messages'] = array(); // An initial record of the number of records to be updated. watchdog('metatag', 'Update 7013: !count records to update.', array('!count' => $sandbox['max']), WATCHDOG_INFO); if (drupal_is_cli()) { drupal_set_message(t('Update 7013: !count records to update.', array('!count' => $sandbox['max']))); } // Last record processed. $sandbox['current_record'] = -1; } // Process records by groups of 10 (arbitrary value). // When a group is processed, the batch update engine determines whether it // should continue processing in the same request or provide progress // feedback to the user and wait for the next request. $limit = 10; // When ran through Drush it's Ok to process a larger number of objects at a // time. if (drupal_is_cli()) { $limit = 100; } // Set default values. for ($ctr = 0; $ctr < $limit; $ctr++) { $sandbox['current_record']++; if (empty($sandbox['records'][$sandbox['current_record']])) { break; } // Shortcuts for later. $entity_type = $sandbox['records'][$sandbox['current_record']]->entity_type; $entity_id = $sandbox['records'][$sandbox['current_record']]->entity_id; // Load the entity. $entities = entity_load($entity_type, array($entity_id)); if (!empty($entities)) { $entity = array_pop($entities); // Make sure that the entity has a language set. if (!empty($entity)) { // If there's a (non-empty) language value, use it. $new_language = entity_language($entity_type, $entity); if (empty($new_language)) { $new_language = LANGUAGE_NONE; } // Update the 'language' value. db_update('metatag') ->fields(array('language' => $new_language)) ->condition('entity_type', $entity_type) ->condition('entity_id', $entity_id) ->execute(); } } // Update our progress information. $sandbox['progress']++; } // Set the "finished" status, to tell batch engine whether this function // needs to run again. If you set a float, this will indicate the progress of // the batch so the progress bar will update. $sandbox['#finished'] = ($sandbox['progress'] >= $sandbox['max']) ? TRUE : ($sandbox['progress'] / $sandbox['max']); if ($sandbox['#finished']) { // Clear all caches so the fixed data will be reloaded. cache_clear_all('*', 'cache_metatag', TRUE); // A final log of the number of records that were converted. watchdog('metatag', 'Update 7013: !count records were updated in total.', array('!count' => $sandbox['progress']), WATCHDOG_INFO); if (drupal_is_cli()) { drupal_set_message(t('Update 7013: !count records were updated.', array('!count' => $sandbox['progress']))); } // hook_update_N() may optionally return a string which will be displayed // to the user. return t('!count records were updated in total.', array('!count' => $sandbox['progress'])); } } /** * Remove duplicate records for a given entity. * * It should be OK to run this without doing a separate batch process as there * shouldn't be many records that have this problem. Hopefully. * * @param $entity_type * The name of an entity type to check for. */ function _metatag_remove_dupes($entity_type) { $purge_count = 0; // First step: fix the records. There should not be multiple records for the // same entity_id with different languages. $dupe_records = db_query("SELECT m.entity_id, count(m.language) AS the_count FROM {metatag} m WHERE m.entity_type = :type GROUP BY m.entity_id HAVING count(m.language) > 1", array(':type' => $entity_type)); if (!empty($dupe_records)) { foreach ($dupe_records as $record) { $entity_id = $record->entity_id; $langs = db_query("SELECT m.entity_id, m.language, m.data FROM {metatag} m WHERE m.entity_type = :type AND m.entity_id = :id", array(':type' => $entity_type, ':id' => $entity_id))->fetchAll(); // Work out which language record to remove. Will need to store this as // an array incase there are multiple records to purge. $langs_to_remove = array(); // Check for duplicate records. // Outer loop starts from the beginning. for ($outer = 0; $outer < count($langs); $outer++) { // This record may have been removed already. if (isset($langs[$outer])) { // Inner loop starts from the end. for ($inner = count($langs) - 1; $inner > 0; $inner--) { // Work out if the outer loop's data is the same as the inner // loop's. if (isset($langs[$inner]) && $langs[$outer]->data == $langs[$inner]->data) { // Remove the second record. $langs_to_remove[] = $langs[$inner]->language; unset($langs[$inner]); } } } } // Only one record left. if (count($langs) == 1) { // This is how it should be, this record is fine. } // More than one record, work out which one to keep. elseif (count($langs) > 1) { // Work out the entity's language. $entity = entity_load($entity_type, $entity_id); $entity_language = entity_language($entity_type, $entity); if (empty($language)) { $entity_language = LANGUAGE_NONE; } // Work out if the entity's language record exists. $lang_pos = NULL; foreach ($langs as $key => $record) { if ($record->language == $entity_language) { $lang_pos = $key; break; } } // If the language record exists, delete the others. if (isset($lang_pos)) { foreach ($langs as $key => $record) { if ($record->language != $entity_language) { $langs_to_remove[] = $record->language; } } } // Otherwise look for a record for the site's default language. else { foreach ($langs as $key => $record) { if ($record->language == $GLOBALS['language']->language) { $lang_pos = $key; break; } } if (isset($lang_pos)) { foreach ($langs as $key => $record) { if ($record->language != $GLOBALS['language']->language) { $langs_to_remove[] = $record->language; } } } // Finally check for LANGUAGE_NONE. else { foreach ($langs as $key => $record) { if ($record->language == LANGUAGE_NONE) { $lang_pos = $key; break; } } if (isset($lang_pos)) { foreach ($langs as $key => $record) { if ($record->language != LANGUAGE_NONE) { $langs_to_remove[] = $record->language; } } } } } } // Purge the redundant records. if (!empty($langs_to_remove)) { $purge_count += db_delete('metatag') ->condition('entity_type', $entity_type) ->condition('entity_id', $entity_id) ->condition('language', $langs_to_remove) ->execute(); } } } if (empty($purge_count)) { drupal_set_message(t('No duplicate :entity_type records were found (this is a good thing).', array(':entity_type' => $entity_type))); watchdog('metatag', 'No duplicate :entity_type records were found (this is a good thing).', array(':entity_type' => $entity_type)); } else { drupal_set_message(t('Purged :count duplicate :entity_type record(s).', array(':count' => $purge_count, ':entity_type' => $entity_type))); watchdog('metatag', 'Purged :count duplicate :entity_type record(s).', array(':count' => $purge_count, ':entity_type' => $entity_type)); return; } } /** * Fix {metatag} records that may have been corrupted by #1871020. */ function metatag_update_7014() { $records = db_query("SELECT * FROM {metatag} m WHERE m.data LIKE :nolang OR m.data LIKE :lang OR m.data LIKE :und", array( ':nolang' => 'a:1:{s:0:"";a:%:{s:%;a:%:{%;}}}', ':lang' => 'a:1:{s:2:"__";a:%:{s:%;a:%:{%;}}}', ':und' => 'a:1:{s:3:"___";a:%:{s:%;a:%:{%;}}}', )); // Nothing to fix. if ($records->rowCount() == 0) { drupal_set_message(t('No corrupt records to fix, this is good news :-)')); } // Fix the faulty records. else { foreach ($records as $record) { // Extract the data and get the first element of the array, this should be // valid data. $record->data = reset(unserialize($record->data)); // Update the record. drupal_write_record('metatag', $record, array('entity_type', 'entity_id', 'language')); } drupal_set_message(t('Fixed @count corrupt meta tag record(s).', array('@count' => $records->rowCount()))); } } /** * Add the revision_id from the entity into metatag schema, adjust the primary * keys accordingly. */ function metatag_update_7015() { if (!db_field_exists('metatag', 'revision_id')) { // Leave a note for metatag_metatags_load_multiple() that the revision_id // field has been added. variable_set('metatag_has_revision_id', TRUE); // Tell update 7017 that it isn't needed. variable_set('metatag_skip_update_7017', TRUE); // Add the new field. db_add_field('metatag', 'revision_id', array( 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, 'description' => 'The revision_id for the entity object this data is attached to.', )); // Remove the existing primary key. This may take some work so it can be // database agnostic, i.e. some databases will not like it. db_drop_primary_key('metatag'); // Add the new primary key. db_add_primary_key('metatag', array('entity_type', 'entity_id', 'revision_id', 'language')); drupal_set_message(t('Added the {metatag}.revision_id field.')); } else { drupal_set_message(t('The {metatag}.revision_id field has already been added, nothing to do.')); } } /** * Update the revision ID to fix the NULL values, help avoid problems with * update 7017. */ function metatag_update_7016() { // It's possible that 7015 was not executed if the site had been updated to // an early dev release, so make sure the revision_id field exists. metatag_update_7015(); // Run the update. db_query("UPDATE {metatag} SET revision_id = 0 WHERE revision_id IS NULL"); } /** * The {metatag}.revision_id field is required. */ function metatag_update_7017() { if (!variable_get('metatag_skip_update_7017', FALSE)) { // Let's add a temporary unique key so MySQL will let it go. db_add_unique_key('metatag', 'temp_key', array('entity_type', 'entity_id', 'revision_id', 'language')); // Now remove the PK before changing a field from serial. db_drop_primary_key('metatag'); // Change the field. db_change_field('metatag', 'revision_id', 'revision_id', array( 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, 'description' => 'The revision_id for the entity object this data is attached to.', )); // Manually re-add the PK. db_add_primary_key('metatag', array('entity_type', 'entity_id', 'revision_id', 'language')); // Finally, remove the temporary unique key because it's no longer useful. db_drop_unique_key('metatag', 'temp_key'); drupal_set_message(t('Fixed the {metatag}.revision_id field.')); } else { drupal_set_message(t("Didn't need to fix the {metatag}.revision_id field; please disperse, nothing to see here.")); } // Delete the temporary variable. variable_del('metatag_skip_update_7017'); } /** * Update the revision ID for each record. This may take some time. Should any * nodes be discovered with a meta tag record for both revision_id 0 and the * correct revision_id, the "0" value will be deleted; if this is not the * desired result the {metatag} table must be manually pruned to have the * correct records prior to letting this update run. */ function metatag_update_7018(&$sandbox) { // Process records in small groups. // When a group is processed, the batch update engine determines whether it // should continue processing in the same request or provide progress // feedback to the user and wait for the next request. $limit = 10; // When ran through Drush it's Ok to process a larger number of objects at a // time. if (drupal_is_cli()) { $limit = 100; } // Use the sandbox at your convenience to store the information needed // to track progression between successive calls to the function. if (!isset($sandbox['progress'])) { // The count of records visited so far. $sandbox['progress'] = 0; // Get a list of all records affected. $sandbox['records'] = db_query("SELECT entity_type, entity_id, language FROM {metatag} WHERE revision_id = 0") ->fetchAll(); // If there's no data, don't bother with the extra work. if (empty($sandbox['records'])) { watchdog('metatag', 'Update 7018: No {metatag} records needed to have the revision_id value fixed.', array(), WATCHDOG_INFO); if (drupal_is_cli()) { drupal_set_message(t('Update 7018: No {metatag} records needed to have the revision_id value fixed.')); } return t('No {metatag} records needed to have the revision_id value fixed.'); } // Total records that must be visited. $sandbox['max'] = count($sandbox['records']); // A place to store messages during the run. $sandbox['messages'] = array(); // An initial record of the number of records to be updated. watchdog('metatag', 'Update 7018: !count records to update.', array('!count' => $sandbox['max']), WATCHDOG_INFO); if (drupal_is_cli()) { drupal_set_message(t('Update 7018: !count records to update.', array('!count' => $sandbox['max']))); } // Last record processed. $sandbox['current_record'] = -1; // Because a lot of other processing happens on the first iteration, just do // one. $limit = 1; } // Work out which entities support languages and revisions. $has_language = array(); $has_revisions = array(); foreach (entity_get_info() as $entity_type => $info) { $has_language[$entity_type] = FALSE; $has_revisions[$entity_type] = FALSE; if (!empty($info['entity keys']['language'])) { $has_language[$entity_type] = $info['entity keys']['language']; } if (!empty($info['entity keys']['revision'])) { $has_revisions[$entity_type] = $info['entity keys']['revision']; } } // Set default values. for ($ctr = 0; $ctr < $limit; $ctr++) { $sandbox['current_record']++; if (empty($sandbox['records'][$sandbox['current_record']])) { break; } // Shortcuts for later. $entity_type = $sandbox['records'][$sandbox['current_record']]->entity_type; $entity_id = $sandbox['records'][$sandbox['current_record']]->entity_id; // Make sure to load the correct language record. $language = $sandbox['records'][$sandbox['current_record']]->language; $conditions = array(); // Some entities don't include a language value. if (!empty($has_language[$entity_type])) { $conditions['language'] = $language; } $records = entity_load($entity_type, array($entity_id), $conditions); // Fix this record. if (!empty($records)) { $entity = reset($records); // Speed up the handling of entities that don't support revisions. $revision_id = 0; if (!empty($has_revisions[$entity_type])) { list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity); $revision_id = intval($revision_id); } // Don't bother updating records if the revision_id is 0. if (!empty($revision_id)) { $exists = db_query("SELECT entity_id FROM {metatag} WHERE entity_type = :entity_type AND entity_id = :entity_id AND revision_id = :revision_id AND language = :language", array( ':entity_type' => $entity_type, ':entity_id' => $entity_id, ':revision_id' => $revision_id, ':language' => $language, ))->fetchObject(); // There isn't already a record for the revision_id, so update the // metatag record. if (!$exists) { db_update('metatag') ->fields(array('revision_id' => $revision_id)) ->condition('entity_type', $entity_type) ->condition('entity_id', $entity_id) ->condition('revision_id', 0) ->condition('language', $language) ->execute(); } // The record exists, so delete the old one under the grounds that the // one with a revision_id is newer. // Disclaimer: this is completely arbitrary, without providing a UI to // let the site maintainer/builder choose which of the two records to // keep, we're stuck with a bad scenario. Thankfully this should not // happen very often and would only affect sites that were running a // dev release. Also, sorry :( else { db_delete('metatag') ->condition('entity_type', $entity_type) ->condition('entity_id', $entity_id) ->condition('revision_id', 0) ->condition('language', $language) ->execute(); } // Nodes can have multiple revisions, so create new {metatag} records // for each of the other revisions. if ($entity_type == 'node') { $revisions = node_revision_list($entity); if (count($revisions) > 1) { $metatags = db_query("SELECT data FROM {metatag} WHERE entity_type = :entity_type AND entity_id = :entity_id AND language = :language", array( ':entity_type' => $entity_type, ':entity_id' => $entity_id, ':language' => $language, )); if (!empty($metatags) && isset($metatags->data) && !empty($metatags->data)) { foreach ($revisions as $vid => $revision) { // Only one record per nid/vid/langcode, thank you. if ($vid != $revision_id) { // Check that there isn't already a record for this revision. $exists = db_query("SELECT entity_id FROM {metatag} WHERE entity_type = :entity_type AND entity_id = :entity_id AND revision_id = :revision_id AND language = :language", array( ':entity_type' => $entity_type, ':entity_id' => $entity_id, ':revision_id' => $vid, ':language' => $language, ))->fetchObject(); if (!$exists) { $node = node_load($entity_id, $vid); $record = new StdClass(); $record->entity_type = $entity_type; $record->entity_id = $entity_id; $record->revision_id = $vid; $record->language = $language; $record->data = $metatags->data; drupal_write_record('metatag', $record); } } } } } } // Other entity types. else { drupal_set_message(t('Metatag records for @type objects have not been checked for revisions.', array('@type' => $entity_type)), 'status', FALSE); } } } // Update our progress information. $sandbox['progress']++; } // Set the "finished" status, to tell batch engine whether this function // needs to run again. If you set a float, this will indicate the progress of // the batch so the progress bar will update. $sandbox['#finished'] = ($sandbox['progress'] >= $sandbox['max']) ? TRUE : ($sandbox['progress'] / $sandbox['max']); if ($sandbox['#finished']) { // Clear all caches so the fixed data will be reloaded. cache_clear_all('*', 'cache_metatag', TRUE); // A final log of the number of records that were converted. watchdog('metatag', 'Update 7018: !count records were updated in total.', array('!count' => $sandbox['progress']), WATCHDOG_INFO); if (drupal_is_cli()) { drupal_set_message(t('Update 7018: !count records were updated.', array('!count' => $sandbox['progress']))); } // hook_update_N() may optionally return a string which will be displayed // to the user. return t('Fixed the revision_id values for !count {metatag} records.', array('!count' => $sandbox['progress'])); } } /** * Clear the entity_cache bins. */ function metatag_update_7019() { if (module_exists('entitycache')) { foreach (drupal_get_schema() as $table_name => $spec) { if (strpos($table_name, 'cache_entity_') === 0) { cache_clear_all('*', $table_name, TRUE); drupal_set_message(t("Cleared the @table cache bin", array('@table' => $table_name))); } } } else { drupal_set_message(t("The EntityCache module is not installed, nothing to do.")); } } /** * Clear the Metatag cache. */ function metatag_update_7020() { cache_clear_all('*', 'cache_metatag', TRUE); return t('All Metatag caches cleared.'); } /** * Clear the existing Metatag cache so all unwanted 403/404 paths can be * purged. */ function metatag_update_7021() { cache_clear_all('*', 'cache_metatag', TRUE); return t('All Metatag caches cleared.'); } /** * A minor bit of tidy-up after update 7015. */ function metatag_update_7022() { variable_del('metatag_skip_update_7015'); } /** * Clear the Metatag cache because $cid_parts was changed. */ function metatag_update_7023() { cache_clear_all('*', 'cache_metatag', TRUE); return t('All Metatag caches cleared.'); } /** * Rename the 'twitter:image' meta tag to 'twitter:image:src', part 1. */ function metatag_update_7024() { // Find all {metatag} records that contained an entry for the old meta tag. $records = db_query("SELECT entity_type, entity_id, revision_id, language, data FROM {metatag} WHERE data LIKE '%twitter:image%'"); // This message will be returned if nothing needed to be updated. $none_message = t('No Metatag entity records needed to have the "twitter:image" meta tag fixed.'); if ($records->rowCount() == 0) { drupal_set_message($none_message); } else { $keys = array('entity_type', 'entity_id', 'revision_id', 'language'); // Loop over the values and correct them. $counter = 0; foreach ($records as $record) { $record->data = unserialize($record->data); if (isset($record->data['twitter:image'])) { $record->data['twitter:image:src'] = $record->data['twitter:image']; unset($record->data['twitter:image']); drupal_write_record('metatag', $record, $keys); $counter++; } } if ($counter == 0) { drupal_set_message($none_message); } else { drupal_set_message(t('Converted the "twitter:image" meta tag for @count entity records to the correct "twitter:image:src" meta tag.', array('@count' => $counter))); } } } /** * Replaced by update 7030. */ function metatag_update_7025() { // Do nothing. } /** * Rename the 'copyright' meta tag to 'rights', part 1. */ function metatag_update_7026() { // Find all {metatag} records that contained an entry for the old meta tag. $records = db_query("SELECT entity_type, entity_id, revision_id, language, data FROM {metatag} WHERE data LIKE '%copyright%'"); // This message will be returned if nothing needed to be updated. $none_message = t('No Metatag entity records needed to have the "copyright" meta tag fixed.'); if ($records->rowCount() == 0) { drupal_set_message($none_message); } else { $keys = array('entity_type', 'entity_id', 'revision_id', 'language'); // Loop over the values and correct them. $counter = 0; foreach ($records as $record) { $record->data = unserialize($record->data); if (isset($record->data['copyright'])) { $record->data['rights'] = $record->data['copyright']; unset($record->data['copyright']); drupal_write_record('metatag', $record, $keys); $counter++; } } if ($counter == 0) { drupal_set_message($none_message); } else { drupal_set_message(t('Converted the "copyright" meta tag for @count entity records to the correct "rights" meta tag.', array('@count' => $counter))); } } } /** * Replaced by update 7031. */ function metatag_update_7027() { // Do nothing. } /** * Clear the menu cache so the new Advanced Settings page will be picked up. */ function metatag_update_7028() { variable_set('menu_rebuild_needed', TRUE); } /** * Add an index to the {metatag} table to speed up some queries. */ function metatag_update_7029() { db_add_index('metatag', 'type_revision', array('entity_type', 'revision_id')); drupal_set_message(t('Added an index to the main Metatag table that will hopefully improve performance a little.')); } /** * Rename the 'twitter:image' meta tag to 'twitter:image:src', part 2. */ function metatag_update_7030() { // Find all {metatag_config} records that contained an entry for the old meta // tag. $records = db_query("SELECT cid, config FROM {metatag_config} WHERE config LIKE '%twitter:image%'"); // This message will be returned if nothing needed to be updated. $none_message = t('No Metatag configuration records needed to have the "twitter:image" meta tag fixed. That said, there may be other configurations elsewhere that do need updating.'); // Loop over the values and correct them. if ($records->rowCount() == 0) { drupal_set_message($none_message); } else { $keys = array('cid'); // Loop over the values and correct them. $counter = 0; foreach ($records as $record) { $record->config = unserialize($record->config); if (isset($record->config['twitter:image'])) { $record->config['twitter:image:src'] = $record->config['twitter:image']; unset($record->config['twitter:image']); drupal_write_record('metatag_config', $record, $keys); $counter++; } } if ($counter == 0) { drupal_set_message($none_message); } else { drupal_set_message(t('Converted the "twitter:image" meta tag for @count configurations to the correct "twitter:image:src" meta tag.', array('@count' => $counter))); } } } /** * Rename the 'copyright' meta tag to 'rights', part 2. */ function metatag_update_7031() { // Find all {metatag_config} records that contained an entry for the old meta // tag. $records = db_query("SELECT cid, config FROM {metatag_config} WHERE config LIKE '%copyright%'"); // This message will be returned if nothing needed to be updated. $none_message = t('No Metatag configuration records needed to have the "copyright" meta tag fixed. That said, there may be other configurations elsewhere that do need updating.'); // Loop over the values and correct them. if ($records->rowCount() == 0) { drupal_set_message($none_message); } else { $keys = array('cid'); // Loop over the values and correct them. $counter = 0; foreach ($records as $record) { $record->config = unserialize($record->config); if (isset($record->config['copyright'])) { $record->config['rights'] = $record->config['copyright']; unset($record->config['copyright']); drupal_write_record('metatag_config', $record, $keys); $counter++; } } if ($counter == 0) { drupal_set_message($none_message); } else { drupal_set_message(t('Converted the "copyright" meta tag for @count configurations to the correct "rights" meta tag.', array('@count' => $counter))); } } } /** * Clear the Metatag cache. */ function metatag_update_7032() { cache_clear_all('*', 'cache_metatag', TRUE); return t('All Metatag caches cleared.'); } /** * These originally removed the 'author' meta tag, but it was subsequently * decided that this was not the correct approach, that the meta tag should not * be removed after all. * * @see https://www.drupal.org/node/2330823 */ function metatag_update_7033() { } function metatag_update_7034() { } function metatag_update_7035() { }