metatag.admin.inc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. <?php
  2. /**
  3. * @file
  4. * Administration page callbacks for the metatag module.
  5. */
  6. function _metatag_config_sort($a, $b) {
  7. $return = NULL;
  8. $a_contexts = explode(':', $a->instance);
  9. $b_contexts = explode(':', $b->instance);
  10. for ($i = 0; $i < max(count($a_contexts), count($b_contexts)); $i++) {
  11. $a_context = isset($a_contexts[$i]) ? $a_contexts[$i] : '';
  12. $b_context = isset($b_contexts[$i]) ? $b_contexts[$i] : '';
  13. if ($a_context == $b_context) {
  14. continue;
  15. }
  16. elseif ($a_context == 'global') {
  17. $return = -1;
  18. }
  19. elseif ($a_context == '') {
  20. $return = -1;
  21. }
  22. else {
  23. $return = strcmp($a_context, $b_context);
  24. }
  25. }
  26. return $return;
  27. }
  28. function _metatag_config_overview_indent($text, $instance) {
  29. $parents = metatag_config_get_parent_instances($instance);
  30. array_shift($parents);
  31. // Add indentation to the leading cell.
  32. if (!empty($parents)) {
  33. $prefix = array_fill(0, count($parents), '<div class="indent">');
  34. $suffix = array_fill(0, count($parents), '</div>');
  35. $text = implode('', $prefix) . $text . implode('', $suffix);
  36. }
  37. return $text;
  38. }
  39. function metatag_config_overview() {
  40. ctools_include('export');
  41. $metatags = metatag_get_info('tags');
  42. $configs = ctools_export_crud_load_all('metatag_config');
  43. ksort($configs);
  44. //uasort($configs, '_metatag_config_sort');
  45. $rows = array();
  46. foreach ($configs as $config) {
  47. $row = array();
  48. // Style disabled configurations differently.
  49. if (!empty($config->disabled)) {
  50. $row['class'][] = 'disabled';
  51. }
  52. $details = '<div class="metatag-config-label collapsed"><a href="#" class="toggle-details">' . check_plain(metatag_config_instance_label($config->instance)) . '</a></div>';
  53. $details .= '<div class="metatag-config-details js-hide">';
  54. $inherits = array();
  55. $parents = metatag_config_get_parent_instances($config->instance);
  56. array_shift($parents);
  57. foreach (array_reverse($parents) as $parent) {
  58. if (!isset($configs[$parent])) {
  59. $rows[$parent] = array(
  60. _metatag_config_overview_indent('<div class="metatag-config-label">' . check_plain(metatag_config_instance_label($parent)) . '</div>', $parent),
  61. '',
  62. );
  63. }
  64. else {
  65. $inherits[$parent] = metatag_config_instance_label($parent);
  66. if (!empty($configs[$parent]->disabled)) {
  67. $inherits[$parent] .= ' ' . t('(disabled)');
  68. }
  69. }
  70. }
  71. // Show how this config inherits from its parents.
  72. if (!empty($inherits)) {
  73. $details .= '<div class="inheritance"><p>' . t('Inherits meta tags from: @parents', array('@parents' => implode(', ', $inherits))) . '</p></div>';
  74. }
  75. // Add a summary of the configuration's defaults.
  76. $summary = array();
  77. foreach ($config->config as $metatag => $data) {
  78. // Skip meta tags that were disabled.
  79. if (empty($metatags[$metatag])) {
  80. continue;
  81. }
  82. $summary[] = array(
  83. check_plain($metatags[$metatag]['label']) . ':',
  84. check_plain(metatag_get_value($metatag, $data, array('raw' => TRUE))),
  85. );
  86. }
  87. if (!empty($summary)) {
  88. $details .= theme('table', array(
  89. 'rows' => $summary,
  90. 'attributes' => array('class' => array('metatag-value-summary')),
  91. ));
  92. }
  93. else {
  94. $details .= '<p class="warning">No overridden default meta tags</p>';
  95. $row['class'][] = 'warning';
  96. }
  97. // Close the details div
  98. $details .= '</div>';
  99. // Add indentation to the leading cell based on how many parents the config has.
  100. $details = _metatag_config_overview_indent($details, $config->instance);
  101. $row['data']['details'] = $details;
  102. $operations = array();
  103. if (metatag_config_access('disable', $config)) {
  104. $operations['edit'] = array(
  105. 'title' => ($config->export_type & EXPORT_IN_DATABASE) ? t('Edit') : t('Override'),
  106. 'href' => 'admin/config/search/metatags/config/' . $config->instance,
  107. );
  108. }
  109. if (metatag_config_access('enable', $config)) {
  110. $operations['enable'] = array(
  111. 'title' => t('Enable'),
  112. 'href' => 'admin/config/search/metatags/config/' . $config->instance . '/enable',
  113. 'query' => array(
  114. 'token' => drupal_get_token('enable-' . $config->instance),
  115. ) + drupal_get_destination(),
  116. );
  117. }
  118. if (metatag_config_access('disable', $config)) {
  119. $operations['disable'] = array(
  120. 'title' => t('Disable'),
  121. 'href' => 'admin/config/search/metatags/config/' . $config->instance . '/disable',
  122. 'query' => array(
  123. 'token' => drupal_get_token('disable-' . $config->instance),
  124. ) + drupal_get_destination(),
  125. );
  126. }
  127. if (metatag_config_access('revert', $config)) {
  128. $operations['revert'] = array(
  129. 'title' => t('Revert'),
  130. 'href' => 'admin/config/search/metatags/config/' . $config->instance . '/revert',
  131. );
  132. }
  133. if (metatag_config_access('delete', $config)) {
  134. $operations['delete'] = array(
  135. 'title' => t('Delete'),
  136. 'href' => 'admin/config/search/metatags/config/' . $config->instance . '/delete',
  137. );
  138. }
  139. $operations['export'] = array(
  140. 'title' => t('Export'),
  141. 'href' => 'admin/config/search/metatags/config/' . $config->instance . '/export',
  142. );
  143. $row['data']['operations'] = array(
  144. 'data' => array(
  145. '#theme' => 'links',
  146. '#links' => $operations,
  147. '#attributes' => array('class' => array('links', 'inline')),
  148. ),
  149. );
  150. $rows[$config->instance] = $row;
  151. }
  152. $build['config_table'] = array(
  153. '#theme' => 'table',
  154. '#header' => array(
  155. 'type' => t('Type'),
  156. 'operations' => t('Operations'),
  157. ),
  158. '#rows' => $rows,
  159. '#empty' => t('No meta tag defaults available yet.'),
  160. '#attributes' => array(
  161. 'class' => array('metatag-config-overview'),
  162. ),
  163. '#attached' => array(
  164. 'js' => array(
  165. drupal_get_path('module', 'metatag') . '/metatag.admin.js',
  166. ),
  167. 'css' => array(
  168. drupal_get_path('module', 'metatag') . '/metatag.admin.css',
  169. ),
  170. ),
  171. );
  172. return $build;
  173. }
  174. /**
  175. * Build an FAPI #options array for the instance select field.
  176. */
  177. function _metatag_config_instance_get_available_options() {
  178. $options = array();
  179. $instances = metatag_config_instance_info();
  180. foreach ($instances as $instance => $instance_info) {
  181. if (metatag_config_load($instance)) {
  182. continue;
  183. }
  184. $parents = metatag_config_get_parent_instances($instance, FALSE);
  185. array_shift($parents);
  186. if (!empty($parents)) {
  187. $parent = reset($parents);
  188. $parent_label = isset($instances[$parent]['label']) ? $instances[$parent]['label'] : t('Unknown');
  189. if (!isset($options[$parent_label])) {
  190. $options[$parent_label] = array();
  191. if (!metatag_config_load($parent)) {
  192. $options[$parent_label][$parent] = t('All');
  193. }
  194. }
  195. $options[$parent_label][$instance] = $instance_info['label'];
  196. unset($options[$parent]);
  197. }
  198. else {
  199. $options[$instance] = $instance_info['label'];
  200. }
  201. }
  202. return $options;
  203. }
  204. function metatag_config_add_form($form, &$form_state) {
  205. $form['instance'] = array(
  206. '#type' => 'select',
  207. '#title' => t('Type'),
  208. '#description' => t('Select the type of default meta tags you would like to add.'),
  209. '#options' => _metatag_config_instance_get_available_options(),
  210. '#required' => TRUE,
  211. );
  212. $form['config'] = array(
  213. '#type' => 'value',
  214. '#value' => array(),
  215. );
  216. $form['actions']['#type'] = 'actions';
  217. $form['actions']['save'] = array(
  218. '#type' => 'submit',
  219. '#value' => t('Add and configure'),
  220. );
  221. $form['actions']['cancel'] = array(
  222. '#type' => 'link',
  223. '#title' => t('Cancel'),
  224. '#href' => isset($_GET['destination']) ? $_GET['destination'] : 'admin/config/search/metatags',
  225. );
  226. return $form;
  227. }
  228. function metatag_config_add_form_submit($form, &$form_state) {
  229. form_state_values_clean($form_state);
  230. $config = (object) $form_state['values'];
  231. metatag_config_save($config);
  232. $form_state['redirect'] = 'admin/config/search/metatags/config/' . $config->instance;
  233. }
  234. function metatag_config_edit_form($form, &$form_state, $config) {
  235. $form['cid'] = array(
  236. '#type' => 'value',
  237. '#value' => !empty($config->cid) ? $config->cid : NULL,
  238. );
  239. $form['instance'] = array(
  240. '#type' => 'value',
  241. '#value' => $config->instance,
  242. );
  243. $contexts = explode(':', $config->instance);
  244. $options['context'] = $contexts[0];
  245. if ($contexts[0] != 'global') {
  246. // The context part of the instance may not map to an entity type, so allow
  247. // the token_get_entity_mapping() function to fallback to the provided type.
  248. if ($token_type = token_get_entity_mapping('entity', $contexts[0], TRUE)) {
  249. $options['token types'] = array($token_type);
  250. }
  251. else {
  252. $options['token types'] = array($contexts[0]);
  253. }
  254. // Allow hook_metatag_token_types_alter() to modify the defined tokens.
  255. drupal_alter('metatag_token_types', $options);
  256. }
  257. // Ensure that this configuration is properly compared to its parent 'default'
  258. // configuration values.
  259. if (count($contexts) > 1) {
  260. // If the config is something like 'node:article' or 'taxonomy_term:tags'
  261. // then the parent default config is 'node' or 'taxonomy_term'.
  262. $default_instance = $contexts;
  263. array_pop($default_instance);
  264. $default_instance = implode(':', $default_instance);
  265. $options['defaults'] = metatag_config_load_with_defaults($default_instance);
  266. }
  267. elseif ($contexts[0] != 'global') {
  268. // If the config is something like 'node' or 'taxonomy_term' then the
  269. // parent default config is 'global'.
  270. $options['defaults'] = metatag_config_load_with_defaults('global');
  271. }
  272. else {
  273. // If the config is 'global' than there are no parent defaults.
  274. $options['defaults'] = array();
  275. }
  276. metatag_metatags_form($form, $config->instance, $config->config, $options);
  277. $form['metatags']['#type'] = 'container';
  278. $form['actions']['#type'] = 'actions';
  279. $form['actions']['save'] = array(
  280. '#type' => 'submit',
  281. '#value' => t('Save'),
  282. );
  283. $form['actions']['cancel'] = array(
  284. '#type' => 'link',
  285. '#title' => t('Cancel'),
  286. '#href' => isset($_GET['destination']) ? $_GET['destination'] : 'admin/config/search/metatags',
  287. );
  288. $form['#submit'][] = 'metatag_config_edit_form_submit';
  289. return $form;
  290. }
  291. function metatag_config_edit_form_submit($form, &$form_state) {
  292. // Build the configuration object and save it.
  293. form_state_values_clean($form_state);
  294. $config = (object) $form_state['values'];
  295. // @todo Consider renaming the config field from 'config' to 'metatags'
  296. $config->config = $config->metatags;
  297. unset($config->metatags);
  298. metatag_config_save($config);
  299. $label = metatag_config_instance_label($config->instance);
  300. drupal_set_message(t('The meta tag defaults for @label have been saved.', array('@label' => $label)));
  301. $form_state['redirect'] = 'admin/config/search/metatags';
  302. }
  303. function metatag_config_enable($config) {
  304. if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], 'enable-' . $config->instance)) {
  305. return MENU_ACCESS_DENIED;
  306. }
  307. ctools_export_crud_enable('metatag_config', $config);
  308. $label = metatag_config_instance_label($config->instance);
  309. drupal_set_message(t('The meta tag defaults for @label have been enabled.', array('@label' => $label)));
  310. drupal_goto();
  311. }
  312. function metatag_config_disable($config) {
  313. if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], 'disable-' . $config->instance)) {
  314. return MENU_ACCESS_DENIED;
  315. }
  316. ctools_export_crud_disable('metatag_config', $config);
  317. $label = metatag_config_instance_label($config->instance);
  318. drupal_set_message(t('The meta tag defaults for @label have been disabed.', array('@label' => $label)));
  319. drupal_goto();
  320. }
  321. function metatag_config_delete_form($form, &$form_state, $config) {
  322. $form['cid'] = array('#type' => 'value', '#value' => $config->cid);
  323. $form['instance'] = array('#type' => 'value', '#value' => $config->instance);
  324. $label = metatag_config_instance_label($config->instance);
  325. $delete = metatag_config_access('delete', $config);
  326. $title = $delete ? t('Are you sure you want to delete the meta tag defaults for @label?', array('@label' => $label)) : t('Are you sure you want to revert the meta tag defaults for @label?', array('@label' => $label));
  327. return confirm_form(
  328. $form,
  329. $title,
  330. 'admin/config/search/metatags',
  331. t('This action cannot be undone.')
  332. );
  333. }
  334. function metatag_config_delete_form_submit($form, &$form_state) {
  335. $config = metatag_config_load($form_state['values']['instance']);
  336. metatag_config_delete($config->instance);
  337. $label = metatag_config_instance_label($config->instance);
  338. $delete = metatag_config_access('delete', $config);
  339. $title = $delete ? t('The meta tag defaults for @label have been deleted.', array('@label' => $label)) : t('The meta tag defaults for @label have been reverted.', array('@label' => $label));
  340. drupal_set_message($title);
  341. $form_state['redirect'] = 'admin/config/search/metatags';
  342. }
  343. function metatag_config_export_form($config) {
  344. ctools_include('export');
  345. return drupal_get_form('ctools_export_form', ctools_export_crud_export('metatag_config', $config), t('Export'));
  346. }
  347. /**
  348. * Form constructor to revert nodes to their default metatags.
  349. *
  350. * @see metatag_bulk_revert_form_submit()
  351. * @ingroup forms
  352. */
  353. function metatag_bulk_revert_form() {
  354. // Get the list of entity:bundle options
  355. $options = array();
  356. foreach (entity_get_info() as $entity_type => $entity_info) {
  357. foreach (array_keys($entity_info['bundles']) as $bundle) {
  358. if (metatag_entity_supports_metatags($entity_type, $bundle)) {
  359. $options[$entity_type . ':' . $bundle] =
  360. $entity_info['label'] . ': ' . $entity_info['bundles'][$bundle]['label'];
  361. }
  362. }
  363. }
  364. $form['update'] = array(
  365. '#type' => 'checkboxes',
  366. '#required' => TRUE,
  367. '#title' => t('Select the entities to revert'),
  368. '#options' => $options,
  369. '#default_value' => array(),
  370. '#description' => t('All meta tags will be removed for all content of the selected entities.'),
  371. );
  372. $form['submit'] = array(
  373. '#type' => 'submit',
  374. '#value' => t('Revert'),
  375. );
  376. return $form;
  377. }
  378. /**
  379. * Form submit handler for metatag reset bulk revert form.
  380. *
  381. * @see metatag_batch_revert_form()
  382. * @see metatag_bulk_revert_batch_finished()
  383. */
  384. function metatag_bulk_revert_form_submit($form, &$form_state) {
  385. $batch = array(
  386. 'title' => t('Bulk updating metatags'),
  387. 'operations' => array(),
  388. 'finished' => 'metatag_bulk_revert_batch_finished',
  389. 'file' => drupal_get_path('module', 'metatag') . '/metatag.admin.inc',
  390. );
  391. // Set a batch operation per entity:bundle.
  392. foreach (array_filter($form_state['values']['update']) as $option) {
  393. list($entity_type, $bundle) = explode(':', $option);
  394. $batch['operations'][] = array('metatag_bulk_revert_batch_operation', array($entity_type, $bundle));
  395. }
  396. batch_set($batch);
  397. }
  398. /**
  399. * Batch callback: delete custom metatags for selected bundles.
  400. */
  401. function metatag_bulk_revert_batch_operation($entity_type, $bundle, &$context) {
  402. if (!isset($context['sandbox']['current'])) {
  403. $context['sandbox']['count'] = 0;
  404. $context['sandbox']['current'] = 0;
  405. }
  406. // Query the selected entity table.
  407. $entity_info = entity_get_info($entity_type);
  408. $query = new EntityFieldQuery();
  409. $query->entityCondition('entity_type', $entity_type)
  410. ->propertyCondition($entity_info['entity keys']['id'], $context['sandbox']['current'], '>')
  411. ->propertyOrderBy($entity_info['entity keys']['id']);
  412. if ($entity_type != 'user') {
  413. /**
  414. * Entities which do not define a bundle such as User fail returning no results.
  415. * @see http://drupal.org/node/1054168#comment-5266208
  416. */
  417. $query->entityCondition('bundle', $bundle);
  418. }
  419. // Get the total amount of entities to process.
  420. if (!isset($context['sandbox']['total'])) {
  421. $context['sandbox']['total'] = $query->count()->execute();
  422. $query->count = FALSE;
  423. // If there are no bundles to revert, stop immediately.
  424. if (!$context['sandbox']['total']) {
  425. $context['finished'] = 1;
  426. return;
  427. }
  428. }
  429. // Process 25 entities per iteration.
  430. $query->range(0, 25);
  431. $result = $query->execute();
  432. $ids = !empty($result[$entity_type]) ? array_keys($result[$entity_type]) : array();
  433. foreach ($ids as $id) {
  434. $metatags = metatag_metatags_load($entity_type, $id);
  435. if (!empty($metatags)) {
  436. db_delete('metatag')->condition('entity_type', $entity_type)
  437. ->condition('entity_id', $id)
  438. ->execute();
  439. metatag_metatags_cache_clear($entity_type, $id);
  440. $context['results'][] = t('Reverted metatags for @bundle with id @id.', array(
  441. '@bundle' => $entity_type . ': ' . $bundle,
  442. '@id' => $id,
  443. ));
  444. }
  445. }
  446. $context['sandbox']['count'] += count($ids);
  447. $context['sandbox']['current'] = max($ids);
  448. if ($context['sandbox']['count'] != $context['sandbox']['total']) {
  449. $context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total'];
  450. }
  451. }
  452. /**
  453. * Batch finished callback.
  454. */
  455. function metatag_bulk_revert_batch_finished($success, $results, $operations) {
  456. if ($success) {
  457. if (!count($results)) {
  458. drupal_set_message(t('No metatags were reverted.'));
  459. }
  460. else {
  461. $message = theme('item_list', array('items' => $results));
  462. drupal_set_message($message);
  463. }
  464. }
  465. else {
  466. $error_operation = reset($operations);
  467. drupal_set_message(t('An error occurred while processing @operation with arguments : @args',
  468. array('@operation' => $error_operation[0], '@args' => print_r($error_operation[0], TRUE))));
  469. }
  470. }