3 namespace Drupal\metatag\Plugin\metatag\Tag;
5 use Drupal\Component\Plugin\PluginBase;
6 use Drupal\Core\Form\FormStateInterface;
7 use Drupal\Core\StringTranslation\StringTranslationTrait;
10 * Each meta tag will extend this base.
12 abstract class MetaNameBase extends PluginBase {
14 use StringTranslationTrait;
17 * Machine name of the meta tag plugin.
24 * Official metatag name.
31 * The title of the plugin.
33 * @var \Drupal\Core\Annotation\Translation
35 * @ingroup plugin_translatable
40 * A longer explanation of what the field is for.
42 * @var \Drupal\Core\Annotation\Translation
44 * @ingroup plugin_translatable
46 protected $description;
49 * The category this meta tag fits in.
56 * Type of the value being stored.
63 * True if URL must use HTTPS.
70 * True if more than one is allowed.
77 * True if the URL value(s) must be absolute.
81 protected $absoluteUrl;
84 * Retrieves the currently active request object.
86 * @var \Symfony\Component\HttpFoundation\Request
91 * The value of the metatag in this instance.
98 * The attribute this tag uses for the name.
102 protected $nameAttribute = 'name';
107 public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
108 parent::__construct($configuration, $plugin_id, $plugin_definition);
110 // Set the properties from the annotation.
111 // @todo Should we have setProperty() methods for each of these?
112 $this->id = $plugin_definition['id'];
113 $this->name = $plugin_definition['name'];
114 $this->label = $plugin_definition['label'];
115 $this->description = $plugin_definition['description'];
116 $this->group = $plugin_definition['group'];
117 $this->weight = $plugin_definition['weight'];
118 $this->type = $plugin_definition['type'];
119 $this->secure = $plugin_definition['secure'];
120 $this->multiple = $plugin_definition['multiple'];
121 $this->absoluteUrl = !empty($plugin_definition['absolute_url']);
122 $this->request = \Drupal::request();
126 * Obtain the meta tag's internal ID.
129 * This meta tag's internal ID.
131 public function id() {
136 * This meta tag's label.
141 public function label() {
146 * The meta tag's description.
149 * This meta tag's description.
151 public function description() {
152 return $this->description;
156 * The meta tag's machine name.
159 * This meta tag's machine name.
161 public function name() {
166 * The meta tag group this meta tag belongs to.
169 * The meta tag's group name.
171 public function group() {
176 * This meta tag's form field's weight.
179 * The form API weight for this. May be any number supported by Form API.
181 public function weight() {
182 return $this->weight;
186 * Obtain this meta tag's type.
189 * This meta tag's type.
191 public function type() {
196 * Whether or not this meta tag must output secure (HTTPS) URLs.
199 * Whether or not this meta tag must output secure (HTTPS) URLs.
201 public function secure() {
202 return $this->secure;
206 * Whether or not this meta tag supports multiple values.
209 * Whether or not this meta tag supports multiple values.
211 public function multiple() {
212 return $this->multiple;
216 * Whether or not this meta tag must output required absolute URLs.
219 * Whether or not this meta tag must output required absolute URLs.
221 public function requiresAbsoluteUrl() {
222 return $this->absoluteUrl;
226 * Whether or not this meta tag is active.
229 * Whether this meta tag has been enabled.
231 public function isActive() {
236 * Generate a form element for this meta tag.
238 * @param array $element
239 * The existing form element to attach to.
242 * The completed form element.
244 public function form(array $element = []) {
246 '#type' => 'textfield',
247 '#title' => $this->label(),
248 '#default_value' => $this->value(),
250 '#required' => isset($element['#required']) ? $element['#required'] : FALSE,
251 '#description' => $this->description(),
252 '#element_validate' => [[get_class($this), 'validateTag']],
255 // Optional handling for items that allow multiple values.
256 if (!empty($this->multiple)) {
257 $form['#description'] .= ' ' . $this->t('Multiple values may be used, separated by a comma. Note: Tokens that return multiple values will be handled automatically.');
260 // Optional handling for images.
261 if ((!empty($this->type())) && ($this->type() === 'image')) {
262 $form['#description'] .= ' ' . $this->t('This will be able to extract the URL from an image field.');
265 if (!empty($this->absolute_url)) {
266 $form['#description'] .= ' ' . $this->t('Any relative or protocol-relative URLs will be converted to absolute URLs.');
269 // Optional handling for secure paths.
270 if (!empty($this->secure)) {
271 $form['#description'] .= ' ' . $this->t('Any links containing http:// will be converted to https://');
278 * Obtain the current meta tag's raw value.
281 * The current raw meta tag value.
283 public function value() {
288 * Assign the current meta tag a value.
290 * @param string $value
291 * The value to assign this meta tag.
293 public function setValue($value) {
294 $this->value = $value;
298 * Make the string presentable.
300 * @param string $value
301 * The raw string to process.
304 * The meta tag value after processing.
306 private function tidy($value) {
311 * Generate the HTML tag output for a meta tag.
313 * @return array|string
314 * A render array or an empty string.
316 public function output() {
317 if (empty($this->value)) {
318 // If there is no value, we don't want a tag output.
319 return $this->multiple() ? [] : '';
322 // Parse out the image URL, if needed.
323 $value = $this->parseImageUrl();
324 $values = $this->multiple() ? explode(',', $value) : [$value];
326 foreach ($values as $value) {
327 $value = $this->tidy($value);
328 if ($this->requiresAbsoluteUrl()) {
330 if (parse_url($value, PHP_URL_HOST) == NULL) {
331 $value = $this->request->getSchemeAndHttpHost() . $value;
333 // Protocol-relative URL.
334 elseif (substr($value, 0, 2) === '//') {
335 $value = $this->request->getScheme() . ':' . $value;
339 // If tag must be secure, convert all http:// to https://.
340 if ($this->secure() && strpos($value, 'http://') !== FALSE) {
341 $value = str_replace('http://', 'https://', $value);
347 $this->nameAttribute => $this->name,
353 return $this->multiple() ? $elements : reset($elements);
357 * Validates the metatag data.
359 * @param array $element
360 * The form element to process.
361 * @param \Drupal\Core\Form\FormStateInterface $form_state
364 public static function validateTag(array &$element, FormStateInterface $form_state) {
365 // @todo If there is some common validation, put it here. Otherwise, make
370 * Extract any image URLs that might be found in a meta tag.
373 * A comma separated list of any image URLs found in the meta tag's value,
374 * or the original string if no images were identified.
376 protected function parseImageUrl() {
377 $value = $this->value();
379 // If this contains embedded image tags, extract the image URLs.
380 if ($this->type() === 'image') {
381 // If image tag src is relative (starts with /), convert to an absolute
382 // link; ignore protocol-relative URLs.
384 if (strpos($value, '<img src="/') !== FALSE && strpos($value, '<img src="//') === FALSE) {
385 $value = str_replace('<img src="/', '<img src="' . $base_root . '/', $value);
388 if ($this->multiple()) {
389 // Split the string into an array, remove empty items.
390 $values = array_filter(explode(',', $value));
396 // Check through the value(s) to see if there are any image tags.
397 foreach ($values as $key => $val) {
399 preg_match('/src="([^"]*)"/', $val, $matches);
400 if (!empty($matches[1])) {
401 $values[$key] = $matches[1];
404 $value = implode(',', $values);
406 // Remove any HTML tags that might remain.
407 $value = strip_tags($value);