metatag.inc 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. <?php
  2. interface DrupalMetaTagInterface {
  3. /**
  4. * Constructor
  5. *
  6. * @param array $info
  7. * The information about the meta tag from metatag_get_info().
  8. */
  9. function __construct(array $info, array $data = array());
  10. function getForm();
  11. //function validateForm();
  12. //function processForm();
  13. function getValue();
  14. function getWeight();
  15. function getElement();
  16. function tidyValue($value);
  17. }
  18. class DrupalDefaultMetaTag implements DrupalMetaTagInterface {
  19. protected $info;
  20. protected $data = array('value' => '');
  21. protected $weight = 0;
  22. function __construct(array $info, array $data = NULL) {
  23. $this->info = $info;
  24. if (isset($data)) {
  25. $this->data = $data;
  26. }
  27. }
  28. /**
  29. * Calculate the weight or this meta tag.
  30. *
  31. * @return integer
  32. */
  33. public function getWeight() {
  34. static $counter = 0;
  35. // If no weight value is found, stack this meta tag at the end.
  36. $weight = 100;
  37. if (!empty($this->info['weight'])) {
  38. $weight = $this->info['weight'];
  39. }
  40. return $weight + ($counter++ * 0.1);
  41. }
  42. public function getForm(array $options = array()) {
  43. return array();
  44. }
  45. public function getValue(array $options = array()) {
  46. return $this->tidyValue($this->data['value']);
  47. }
  48. public function getElement(array $options = array()) {
  49. $value = $this->getValue($options);
  50. if (strlen($value) === 0) {
  51. return array();
  52. }
  53. // The stack of elements that will be output.
  54. $elements = array();
  55. // Dynamically add each option to this setting.
  56. $base_element = isset($this->info['element']) ? $this->info['element'] : array();
  57. // Single item.
  58. if (empty($this->info['multiple'])) {
  59. $values = array($value);
  60. }
  61. // Multiple items.
  62. else {
  63. $values = array_filter(explode(',', $value));
  64. }
  65. // Loop over each item.
  66. if (!empty($values)) {
  67. foreach ($values as $ctr => $value) {
  68. $value = trim($value);
  69. // Some meta tags must be output as secure URLs.
  70. if (!empty($this->info['secure'])) {
  71. $value = str_replace('http://', 'https://', $value);
  72. }
  73. // Combine the base configuration for this meta tag with the value.
  74. $element = $base_element + array(
  75. '#theme' => 'metatag',
  76. '#tag' => 'meta',
  77. '#id' => 'metatag_' . $this->info['name'] . '_' . $ctr,
  78. '#name' => $this->info['name'],
  79. '#value' => $value,
  80. '#weight' => $this->getWeight(),
  81. );
  82. // Add header information if desired.
  83. if (!empty($this->info['header'])) {
  84. $element['#attached']['drupal_add_http_header'][] = array($this->info['header'], $value);
  85. }
  86. $elements[] = array($element, $element['#id']);
  87. }
  88. }
  89. if (!empty($elements)) {
  90. return array(
  91. '#attached' => array('drupal_add_html_head' => $elements),
  92. );
  93. }
  94. }
  95. /**
  96. * Remove unwanted formatting from a meta tag.
  97. *
  98. * @param $value string
  99. * The meta tag value to be tidied up.
  100. *
  101. * @return string
  102. * The meta tag value after it has been tidied up.
  103. */
  104. public function tidyValue($value) {
  105. // Specifically replace encoded spaces, because some WYSIWYG editors are
  106. // silly. Do this before decoding the other HTML entities so that the output
  107. // doesn't end up with a bunch of a-circumflex characters.
  108. $value = str_replace('&nbsp;', ' ', $value);
  109. // Convert any HTML entities into regular characters.
  110. $value = decode_entities($value);
  111. // Remove any HTML code that might have been included.
  112. $value = strip_tags($value);
  113. // Strip errant whitespace.
  114. $value = str_replace(array("\r\n", "\n", "\r", "\t"), ' ', $value);
  115. $value = str_replace(' ', ' ', $value);
  116. $value = str_replace(' ', ' ', $value);
  117. $value = trim($value);
  118. return $value;
  119. }
  120. }
  121. /**
  122. * Text-based meta tag controller.
  123. */
  124. class DrupalTextMetaTag extends DrupalDefaultMetaTag {
  125. public function getForm(array $options = array()) {
  126. $options += array(
  127. 'token types' => array(),
  128. );
  129. $form['value'] = isset($this->info['form']) ? $this->info['form'] : array();
  130. $form['value'] += array(
  131. '#type' => 'textfield',
  132. '#title' => $this->info['label'],
  133. '#description' => !empty($this->info['description']) ? $this->info['description'] : '',
  134. '#default_value' => isset($this->data['value']) ? $this->data['value'] : '',
  135. '#element_validate' => array('token_element_validate'),
  136. '#token_types' => $options['token types'],
  137. '#maxlength' => 1024,
  138. );
  139. if (!empty($this->info['multiple'])) {
  140. $form['value']['#description'] .= ' ' . t('Multiple values may be used, separated by a comma. Note: Tokens that return multiple values will be handled automatically.');
  141. }
  142. // Support for dependencies, using Form API's #states system.
  143. // @see metatag.api.php.
  144. // @see https://api.drupal.org/drupal_process_states
  145. if (!empty($this->info['dependencies'])) {
  146. foreach ($this->info['dependencies'] as $specs) {
  147. $form['value']['#states']['visible'][':input[name*="[' . $specs['dependency'] . '][' . $specs['attribute'] . ']"]'] = array(
  148. $specs['condition'] => $specs['value'],
  149. );
  150. }
  151. }
  152. return $form;
  153. }
  154. public function getValue(array $options = array()) {
  155. $options += array(
  156. 'instance' => '',
  157. 'token data' => array(),
  158. 'clear' => TRUE,
  159. 'sanitize' => TRUE,
  160. 'raw' => FALSE,
  161. );
  162. $name = "metatag:" . $options["instance"] . ":" . $this->info["name"];
  163. $value = metatag_translate($name, $this->data['value']);
  164. if (empty($options['raw'])) {
  165. // Give other modules the opportunity to use hook_metatag_pattern_alter()
  166. // to modify defined token patterns and values before replacement.
  167. drupal_alter('metatag_pattern', $value, $options['token data'], $this->info['name']);
  168. $value = token_replace($value, $options['token data'], $options);
  169. }
  170. return $this->tidyValue($value);
  171. }
  172. }
  173. /**
  174. * Link type meta tag controller.
  175. */
  176. class DrupalLinkMetaTag extends DrupalTextMetaTag {
  177. public function getElement(array $options = array()) {
  178. $element = isset($this->info['element']) ? $this->info['element'] : array();
  179. $value = $this->getValue($options);
  180. if (strlen($value) === 0) {
  181. return array();
  182. }
  183. $element += array(
  184. '#theme' => 'metatag_link_rel',
  185. '#tag' => 'link',
  186. '#id' => 'metatag_' . $this->info['name'],
  187. '#name' => $this->info['name'],
  188. '#value' => $value,
  189. '#weight' => $this->getWeight(),
  190. );
  191. if (!isset($this->info['header']) || !empty($this->info['header'])) {
  192. // Also send the generator in the HTTP header.
  193. // @todo This does not support 'rev' or alternate link headers.
  194. $element['#attached']['drupal_add_http_header'][] = array('Link', '<' . $value . '>;' . drupal_http_header_attributes(array('rel' => $element['#name'])), TRUE);
  195. }
  196. return array(
  197. '#attached' => array('drupal_add_html_head' => array(array($element, $element['#id']))),
  198. );
  199. }
  200. }
  201. /**
  202. * Title meta tag controller.
  203. *
  204. * This extends DrupalTextMetaTag as we need to alter variables in
  205. * template_preprocess_html() rather output a normal meta tag.
  206. */
  207. class DrupalTitleMetaTag extends DrupalTextMetaTag {
  208. public function getElement(array $options = array()) {
  209. $element = array();
  210. $value = $this->getValue($options);
  211. $element['#attached']['metatag_set_preprocess_variable'][] = array('html', 'head_title', $value);
  212. $element['#attached']['metatag_set_preprocess_variable'][] = array('html', 'head_array', array('title' => $value));
  213. return $element;
  214. }
  215. }
  216. /**
  217. * Multiple value meta tag controller.
  218. */
  219. class DrupalListMetaTag extends DrupalDefaultMetaTag {
  220. function __construct(array $info, array $data = NULL) {
  221. // Ensure that the $data['value] argument is an array.
  222. if (empty($data['value'])) {
  223. $data['value'] = array();
  224. }
  225. $data['value'] = (array) $data['value'];
  226. parent::__construct($info, $data);
  227. }
  228. public function getForm(array $options = array()) {
  229. $form['value'] = isset($this->info['form']) ? $this->info['form'] : array();
  230. $form['value'] += array(
  231. '#type' => 'checkboxes',
  232. '#title' => $this->info['label'],
  233. '#description' => !empty($this->info['description']) ? $this->info['description'] : '',
  234. '#default_value' => isset($this->data['value']) ? $this->data['value'] : array(),
  235. );
  236. return $form;
  237. }
  238. public function getValue(array $options = array()) {
  239. $values = array_keys(array_filter($this->data['value']));
  240. sort($values);
  241. $value = implode(', ', $values);
  242. return $this->tidyValue($value);
  243. }
  244. }
  245. /**
  246. * Date interval meta tag controller.
  247. */
  248. class DrupalDateIntervalMetaTag extends DrupalDefaultMetaTag {
  249. public function getForm(array $options = array()) {
  250. $form['value'] = array(
  251. '#type' => 'textfield',
  252. '#title' => t('@title interval', array('@title' => $this->info['label'])),
  253. '#default_value' => isset($this->data['value']) ? $this->data['value'] : '',
  254. '#element_validate' => array('element_validate_integer_positive'),
  255. '#maxlength' => 4,
  256. '#description' => isset($this->info['description']) ? $this->info['description'] : '',
  257. );
  258. $form['period'] = array(
  259. '#type' => 'select',
  260. '#title' => t('@title interval type', array('@title' => $this->info['label'])),
  261. '#default_value' => isset($this->data['period']) ? $this->data['period'] : '',
  262. '#options' => array(
  263. '' => t('- none -'),
  264. 'day' => t('Day(s)'),
  265. 'week' => t('Week(s)'),
  266. 'month' => t('Month(s)'),
  267. 'year' => t('Year(s)'),
  268. ),
  269. );
  270. return $form;
  271. }
  272. public function getValue(array $options = array()) {
  273. $value = '';
  274. if (!empty($this->data['value'])) {
  275. $interval = intval($this->data['value']);
  276. if (!empty($interval) && !empty($this->data['period'])) {
  277. $period = $this->data['period'];
  278. $value = format_plural($interval, '@count ' . $period, '@count ' . $period . 's');
  279. }
  280. }
  281. return $value;
  282. }
  283. }