metatag.install 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. <?php
  2. /**
  3. * @file
  4. * Install, update and uninstall functions for the metatag module.
  5. */
  6. /**
  7. * Implements hook_install().
  8. */
  9. function metatag_install() {
  10. // Don't display the message during site installation, it looks funny.
  11. if (!drupal_installation_attempted()) {
  12. drupal_set_message(t("To adjust global defaults, go to admin/config/search/metatag. If you need to set meta tags for a specific entity, edit its bundle and add the Metatag field."));
  13. }
  14. }
  15. /**
  16. * Implements hook_requirements().
  17. */
  18. function metatag_requirements($phase) {
  19. $requirements = [];
  20. if ($phase == 'runtime') {
  21. // Recommend the Schema.org Metatag module.
  22. if (!\Drupal::moduleHandler()->moduleExists('schema_metatag')) {
  23. $requirements['metatag_schema'] = [
  24. 'severity' => REQUIREMENT_INFO,
  25. 'title' => 'Metatag',
  26. 'value' => t('Schema.org Metatag is recommended'),
  27. 'description' => t('The <a href="@module">Schema.org Metatag</a> module is highly recommended to add <a href="@jsonld">JSON-LD</a> -formatted <a href="@schema">schema.org</a> compatible data structures to the site.', [
  28. '@module' => 'https://www.drupal.org/project/schema_metatag',
  29. '@jsonld' => 'https://json-ld.org',
  30. '@schema' => 'http://schema.org',
  31. ]),
  32. ];
  33. }
  34. else {
  35. $requirements['metatag_schema'] = [
  36. 'severity' => REQUIREMENT_OK,
  37. 'title' => 'Metatag',
  38. 'value' => t('Schema.org Metatag is installed'),
  39. 'description' => t('The <a href="@module">Schema.org Metatag</a> module is installed.', [
  40. '@module' => 'https://www.drupal.org/project/schema_metatag',
  41. ]),
  42. ];
  43. }
  44. }
  45. return $requirements;
  46. }
  47. /**
  48. * Remove tags in field storage that match default or are empty.
  49. */
  50. function metatag_update_8101() {
  51. // Get all of the field storage entities of type metatag.
  52. $field_storage_configs = \Drupal::entityTypeManager()
  53. ->getStorage('field_storage_config')
  54. ->loadByProperties(['type' => 'metatag']);
  55. foreach ($field_storage_configs as $field_storage) {
  56. $field_name = $field_storage->getName();
  57. // Get the individual fields (field instances) associated with bundles.
  58. $fields = \Drupal::entityTypeManager()
  59. ->getStorage('field_config')
  60. ->loadByProperties(['field_name' => $field_name]);
  61. // For each of the fields, delete all records that match the defaults.
  62. foreach ($fields as $field) {
  63. // Get the bundle this field is attached to.
  64. $bundle = $field->getTargetBundle();
  65. // Get the default value for this field on this bundle.
  66. $field_default_tags_value = $field->getDefaultValueLiteral();
  67. $field_default_tags_value = $field_default_tags_value[0]['value'];
  68. // Determine the table and "value" field names.
  69. $field_table = "node__" . $field_name;
  70. $field_value_field = $field_name . "_value";
  71. // Delete all records where the field value and default are identical.
  72. \Drupal::database()->delete($field_table)
  73. ->condition('bundle', $bundle, '=')
  74. ->condition($field_value_field, $field_default_tags_value, '=')
  75. ->execute();
  76. }
  77. }
  78. return t('Removed all default meta tag records so they can be automatically inherited when the page is loaded.');
  79. }
  80. /**
  81. * Remove tags in field storage that match default or are empty.
  82. */
  83. function metatag_update_8102(&$sandbox) {
  84. // This whole top section only needs to be done the first time.
  85. if (!isset($sandbox['records_processed'])) {
  86. $sandbox['records_processed'] = 0;
  87. $sandbox['total_records'] = 0;
  88. $sandbox['current_field'] = 0;
  89. $sandbox['current_record'] = 0;
  90. // Counter to enumerate the fields so we can access them in the array
  91. // by number rather than name.
  92. $field_counter = 0;
  93. // Get all of the field storage entities of type metatag.
  94. $field_storage_configs = \Drupal::entityTypeManager()
  95. ->getStorage('field_storage_config')
  96. ->loadByProperties(['type' => 'metatag']);
  97. foreach ($field_storage_configs as $field_storage) {
  98. $field_name = $field_storage->getName();
  99. // Get the individual fields (field instances) associated with bundles.
  100. $fields = \Drupal::entityTypeManager()
  101. ->getStorage('field_config')
  102. ->loadByProperties(['field_name' => $field_name]);
  103. // For each of the fields, do the mass delete of exact matches but
  104. // store the overridden records in the sandbox to be batch processed.
  105. foreach ($fields as $field) {
  106. // Get the bundle this field is attached to.
  107. $bundle = $field->getTargetBundle();
  108. // Get the default value for this field on this bundle.
  109. $field_default_tags_value = $field->getDefaultValueLiteral();
  110. $field_default_tags_value = $field_default_tags_value[0]['value'];
  111. $field_default_tags = unserialize($field_default_tags_value);
  112. // Determine the table and "value" field names.
  113. $field_table = "node__" . $field_name;
  114. $field_value_field = $field_name . "_value";
  115. // Get all records where the field data does not match the default.
  116. $query = \Drupal::database()->select($field_table);
  117. $query->addField($field_table, 'entity_id');
  118. $query->addField($field_table, 'revision_id');
  119. $query->addField($field_table, 'langcode');
  120. $query->addField($field_table, $field_value_field);
  121. $query->condition('bundle', $bundle, '=');
  122. $result = $query->execute();
  123. $records = $result->fetchAll();
  124. // Fill in all the sandbox information so we can batch the individual
  125. // record comparing and updating.
  126. $sandbox['fields'][$field_counter]['field_table'] = $field_table;
  127. $sandbox['fields'][$field_counter]['field_value_field'] = $field_value_field;
  128. $sandbox['fields'][$field_counter]['field_default_tags'] = $field_default_tags;
  129. $sandbox['fields'][$field_counter]['records'] = $records;
  130. $sandbox['total_records'] += count($sandbox['fields'][$field_counter]['records'] = $records);
  131. $field_counter++;
  132. }
  133. }
  134. }
  135. if ($sandbox['total_records'] == 0) {
  136. // No partially overridden fields so we can skip the whole batch process.
  137. $sandbox['#finished'] = 1;
  138. }
  139. else {
  140. // Begin the batch processing of individual field records.
  141. $max_per_batch = 10;
  142. $counter = 1;
  143. $current_field = $sandbox['current_field'];
  144. $current_field_records = $sandbox['fields'][$current_field]['records'];
  145. $current_record = $sandbox['current_record'];
  146. $field_table = $sandbox['fields'][$current_field]['field_table'];
  147. $field_value_field = $sandbox['fields'][$current_field]['field_value_field'];
  148. $field_default_tags = $sandbox['fields'][$current_field]['field_default_tags'];
  149. // Loop through the field(s) and remove any field data that matches the
  150. // field default for that bundle. Because the ability to override a default
  151. // with "nothing" didn't exist prior to this and because any tag that had
  152. // a default of "nothing" would have that also in the field data, we are
  153. // removing those as well.
  154. while ($counter <= $max_per_batch && $record = $current_field_records[$current_record]) {
  155. // Strip any empty tags or ones matching the field's defaults and leave
  156. // only the overridden tags in $new_tags.
  157. $current_tags = unserialize($record->$field_value_field);
  158. $new_tags = [];
  159. foreach ($current_tags as $key => $tag) {
  160. if (!empty($tag) && $field_default_tags[$key] != $tag) {
  161. $new_tags[$key] = $tag;
  162. }
  163. }
  164. if (empty($new_tags)) {
  165. // All tags were either empty or matched the default so the record can
  166. // be deleted.
  167. \Drupal::database()->delete($field_table)
  168. ->condition('entity_id', $record->entity_id)
  169. ->condition('revision_id', $record->revision_id)
  170. ->condition('langcode', $record->langcode)
  171. ->execute();
  172. }
  173. else {
  174. // There are some overridden tags so update the record with just those.
  175. $tags_string = serialize($new_tags);
  176. \Drupal::database()->update($field_table)
  177. ->fields([
  178. $field_value_field => $tags_string,
  179. ])
  180. ->condition('entity_id', $record->entity_id)
  181. ->condition('revision_id', $record->revision_id)
  182. ->condition('langcode', $record->langcode)
  183. ->execute();
  184. }
  185. $counter++;
  186. $current_record++;
  187. }
  188. // We ran out of records for the field so start the next batch out with the
  189. // next field.
  190. if (!isset($current_field_records[$current_record])) {
  191. $current_field++;
  192. $current_record = 0;
  193. }
  194. // We have finished all the fields. All done.
  195. if (!isset($sandbox['fields'][$current_field])) {
  196. $sandbox['records_processed'] += $counter - 1;
  197. $sandbox['#finished'] = 1;
  198. }
  199. // Update the sandbox values to prepare for the next round.
  200. else {
  201. $sandbox['current_field'] = $current_field;
  202. $sandbox['current_record'] = $current_record;
  203. $sandbox['records_processed'] += $counter - 1;
  204. $sandbox['#finished'] = $sandbox['records_processed'] / $sandbox['total_records'];
  205. }
  206. }
  207. if ($sandbox['total_records'] > 0) {
  208. return (string) t('Processed @processed of @total overridden Metatag records.', [
  209. '@processed' => $sandbox['records_processed'],
  210. '@total' => $sandbox['total_records'],
  211. ]);
  212. }
  213. else {
  214. return (string) t("There were no overridden Metatag records.");
  215. }
  216. }
  217. /**
  218. * Move field defaults to Metatag Defaults.
  219. */
  220. function metatag_update_8103() {
  221. $config_installer = \Drupal::service('config.installer');
  222. $entity_manager = \Drupal::entityTypeManager();
  223. // 1. Install cofiguration.
  224. $sync_status = $config_installer->isSyncing();
  225. if ($sync_status) {
  226. $source_storage = $config_installer->getSourceStorage();
  227. }
  228. // Clear plugin manager caches.
  229. \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions();
  230. // Install default configuration of the module.
  231. if ($sync_status) {
  232. $config_installer
  233. ->setSyncing(TRUE)
  234. ->setSourceStorage($source_storage);
  235. }
  236. // Install new configuration for Metatag.
  237. $config_installer->installDefaultConfig('module', 'metatag');
  238. // Apply all entity definition changes.
  239. \Drupal::entityDefinitionUpdateManager()->applyUpdates();
  240. // 2. Extract Metatag field defaults.
  241. $entity_info = $entity_manager->getDefinitions();
  242. $tags = [];
  243. // Get all of the field storage entities of type metatag.
  244. $field_storage_configs = $entity_manager
  245. ->getStorage('field_storage_config')
  246. ->loadByProperties(['type' => 'metatag']);
  247. foreach ($field_storage_configs as $field_storage) {
  248. $field_name = $field_storage->getName();
  249. // Get the individual fields (field instances) associated with bundles.
  250. $fields = $entity_manager->getStorage('field_config')
  251. ->loadByProperties(['field_name' => $field_name]);
  252. foreach ($fields as $field) {
  253. // Adjust the config id depending on whether these are entity defaults
  254. // or bundle defaults.
  255. $entity_type = $field->getTargetEntityTypeId();
  256. $bundle = $field->getTargetBundle();
  257. $metatag_defaults_id = $entity_type;
  258. if ($entity_type != $bundle) {
  259. // This is a bundle override.
  260. $metatag_defaults_id = $entity_type . '__' . $bundle;
  261. }
  262. // Extract field default values.
  263. $field_default_tags_value = $field->getDefaultValueLiteral();
  264. $field_default_tags_value = unserialize($field_default_tags_value[0]['value']);
  265. $field_default_tags_value = array_filter($field_default_tags_value);
  266. // Don't bother copying empty values.
  267. if (!empty($field_default_tags_value)) {
  268. $tags[$metatag_defaults_id] = $field_default_tags_value;
  269. }
  270. }
  271. }
  272. // 3. Create Config entities with field default values.
  273. if (!empty($tags)) {
  274. $bundleInfoManager = \Drupal::service('entity_type.bundle.info');
  275. foreach ($tags as $metatag_defaults_id => $values) {
  276. list($entity_type, $entity_bundle) = explode('__', $metatag_defaults_id);
  277. $entity_label = (string) $entity_info[$entity_type]->get('label');
  278. $bundle_info = $bundleInfoManager->getBundleInfo($entity_type);
  279. $bundle_label = $bundle_info[$entity_bundle]['label'];
  280. $label = $entity_label . ': ' . $bundle_label;
  281. $metatags_global_manager = $entity_manager->getStorage('metatag_defaults');
  282. $entity = $metatags_global_manager->load($metatag_defaults_id);
  283. if ($entity) {
  284. // These are defaults for an existing config entity, such as User.
  285. $entity->set('tags', $values);
  286. }
  287. else {
  288. // These are bundle overrides.
  289. $entity = $metatags_global_manager->create([
  290. 'id' => $metatag_defaults_id,
  291. 'label' => $label,
  292. 'tags' => $values,
  293. ]);
  294. }
  295. $entity->save();
  296. }
  297. return (string) t("@count Metatag field defaults have been converted to using global entity defaults.", ['@count' => count($tags)]);
  298. }
  299. else {
  300. return (string) t("There were Metatag field configurations that needed to be converted.");
  301. }
  302. }
  303. /**
  304. * Rebuild routes after moving Metatag admin from Structure to Config.
  305. */
  306. function metatag_update_8104() {
  307. \Drupal::service('router.builder')->setRebuildNeeded();
  308. }
  309. /**
  310. * Rebuild routes after renaming.
  311. */
  312. function metatag_update_8105() {
  313. \Drupal::service('router.builder')->setRebuildNeeded();
  314. }
  315. /**
  316. * Add the metatag_defaults config entity to the site.
  317. */
  318. function metatag_update_8106() {
  319. \Drupal::entityDefinitionUpdateManager()->applyUpdates();
  320. }
  321. /**
  322. * Enable the new metatag_open_graph module.
  323. */
  324. function metatag_update_8107() {
  325. \Drupal::service('module_installer')->install(['metatag_open_graph']);
  326. return (string) t("The new Metatag: Open Graph module has been enabled.");
  327. }