diff --git a/CHANGELOG.md b/CHANGELOG.md index 66b25583..090515de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. The format ### Added +- Improved title in entities (e.g. automated " - lernen mit Serlo" suffix) ([#678](https://github.com/serlo-org/athene2/pull/678)) - Add `package.json` so that we can use `yarn` as task runner - Add yarn script `start` that executes `docker-compose up` - Add yarn script `format:prettier` that executes prettier (formats Markdown, YAML, JSON, etc.) @@ -16,6 +17,8 @@ All notable changes to this project will be documented in this file. The format - Make list of unrevised revisions (e.g. https://de.serlo.org/mathe/entity/unrevised) faster ([#790](https://github.com/serlo-org/athene2/pull/790), [#780](https://github.com/serlo-org/athene2/pull/780)) - Show all unrevised revisions of an entity (and not only the newest one) ([#790](https://github.com/serlo-org/athene2/pull/790)) +- Show a subject-specific Open Graph meta image (e.g. for Facebook previews) ([#678](https://github.com/serlo-org/athene2/pull/678)) +- Expose a tenant-spefiic Open Search description file ([#678](https://github.com/serlo-org/athene2/pull/678)) ## [Build 2] - 2017-10-30 diff --git a/src/config/autoload/local.php.dist b/src/config/autoload/local.php.dist index d4077f8f..1787cc17 100644 --- a/src/config/autoload/local.php.dist +++ b/src/config/autoload/local.php.dist @@ -58,14 +58,14 @@ return [ 'slogan' => 'Freie Bildung.', 'description' => 'Serlo ist eine kostenlose Plattform mit freien Lernmaterialien, die alle mitgestalten können.', 'logo' => '', - 'head_title' => 'Serlo.org' + 'head_title' => 'lernen mit Serlo!' ], 'english' => [ 'name' => '
Serlo
', 'slogan' => 'Open Education.', 'description' => 'Serlo is a free service with open educational resources, which anyone can contribute to.', 'logo' => '', - 'head_title' => 'Serlo.org' + 'head_title' => 'lernen mit Serlo!' ] ] ], diff --git a/src/config/autoload/serlo.config.local.php.dist b/src/config/autoload/serlo.config.local.php.dist index 2cd6cc6e..7b12d00c 100644 --- a/src/config/autoload/serlo.config.local.php.dist +++ b/src/config/autoload/serlo.config.local.php.dist @@ -28,14 +28,14 @@ return [ 'slogan' => 'Die freie Lernplattform', 'description' => 'Serlo ist eine kostenlose Plattform mit freien Lernmaterialien, die alle mitgestalten können.', 'logo' => '', - 'head_title' => 'Serlo.org' + 'head_title' => 'lernen mit Serlo!' ], 'english' => [ 'name' => '
Serlo
', 'slogan' => 'The Open Learning Platform', 'description' => 'Serlo is a free service with open educational resources, which anyone can contribute to.', 'logo' => '', - 'head_title' => 'Serlo.org' + 'head_title' => 'lernen mit Serlo!' ] ] ], diff --git a/src/module/Normalizer/src/Normalizer/Adapter/AbstractAdapter.php b/src/module/Normalizer/src/Normalizer/Adapter/AbstractAdapter.php index 794beb76..d8b6cd3f 100644 --- a/src/module/Normalizer/src/Normalizer/Adapter/AbstractAdapter.php +++ b/src/module/Normalizer/src/Normalizer/Adapter/AbstractAdapter.php @@ -25,9 +25,11 @@ use Normalizer\Entity\Normalized; use DateTime; use Normalizer\Exception\RuntimeException; +use Zend\I18n\Translator\TranslatorAwareTrait; abstract class AbstractAdapter implements AdapterInterface { + use TranslatorAwareTrait; protected $object; public function getObject() @@ -60,11 +62,13 @@ public function normalize($object) 'routeParams' => $this->getRouteParams(), 'id' => $this->getId(), 'metadata' => [ - 'creationDate' => $this->getCreationDate() ? $this->getCreationDate() : new DateTime(), - 'description' => $this->getDescription(), - 'keywords' => $this->getKeywords(), - 'lastModified' => $this->getLastModified() ? $this->getLastModified() : new DateTime(), - 'robots' => $this->isTrashed() ? 'noindex' : 'all', + 'title' => $this->getHeadTitle(), + 'creationDate' => $this->getCreationDate() ? $this->getCreationDate() : new DateTime(), + 'description' => $this->getDescription(), + 'metaDescription' => $this->getMetaDescription(), + 'keywords' => $this->getKeywords(), + 'lastModified' => $this->getLastModified() ? $this->getLastModified() : new DateTime(), + 'robots' => $this->isTrashed() ? 'noindex' : 'all', ], ]); @@ -89,6 +93,14 @@ protected function getDescription() return $this->getContent(); } + /** + * @return string + */ + protected function getMetaDescription() + { + return $this->getDescription(); + } + /** * @return DateTime */ @@ -136,4 +148,12 @@ abstract protected function getType(); * @return boolean */ abstract protected function isTrashed(); + + /** + * @return string + */ + protected function getHeadTitle() + { + return $this->getTitle(); + } } diff --git a/src/module/Normalizer/src/Normalizer/Adapter/AdapterInterface.php b/src/module/Normalizer/src/Normalizer/Adapter/AdapterInterface.php index 403d3b7a..1892a4bd 100644 --- a/src/module/Normalizer/src/Normalizer/Adapter/AdapterInterface.php +++ b/src/module/Normalizer/src/Normalizer/Adapter/AdapterInterface.php @@ -23,8 +23,9 @@ namespace Normalizer\Adapter; use Normalizer\Entity\NormalizedInterface; +use Zend\I18n\Translator\TranslatorAwareInterface; -interface AdapterInterface +interface AdapterInterface extends TranslatorAwareInterface { /** * @param object $object diff --git a/src/module/Normalizer/src/Normalizer/Adapter/EntityAdapter.php b/src/module/Normalizer/src/Normalizer/Adapter/EntityAdapter.php index a841e0dd..988fc40c 100644 --- a/src/module/Normalizer/src/Normalizer/Adapter/EntityAdapter.php +++ b/src/module/Normalizer/src/Normalizer/Adapter/EntityAdapter.php @@ -160,4 +160,45 @@ protected function isTrashed() { return $this->getObject()->isTrashed(); } + + protected function getHeadTitle() + { + $maxStringLen = 65; + + $type = $this->getType(); + $typeName = $this->getTranslator()->translate($type); + + $titleFallback = $this->getTitle(); + $title = $this->getField('meta_title'); + if ($title === $this->getId()) { + $title = $titleFallback; + } + + if ($type === 'course-page') { + $parent = $this->getObject()->getParents('link')->first(); + $parentAdapter = new EntityAdapter(); + $parentAdapter->setTranslator($this->translator); + $normalizedParent = $parentAdapter->normalize($parent); + $parentTitle = $normalizedParent->getMetadata()->getTitle(); + $title = $parentTitle . " | " .$title; + } + + //add "(Kurs)" etc + if ($type !== 'article') { + if (strlen($title) < ($maxStringLen-strlen($typeName))) { + $title .= ' (' . $typeName . ')'; + } + } + + return $title; + } + + protected function getMetaDescription() + { + $description = $this->getField('meta_description'); + if ($description === $this->getId()) { + $description = $this->getDescription(); + } + return $description; + } } diff --git a/src/module/Normalizer/src/Normalizer/Adapter/TaxonomyTermAdapter.php b/src/module/Normalizer/src/Normalizer/Adapter/TaxonomyTermAdapter.php index ca34fa6e..778d5dbd 100644 --- a/src/module/Normalizer/src/Normalizer/Adapter/TaxonomyTermAdapter.php +++ b/src/module/Normalizer/src/Normalizer/Adapter/TaxonomyTermAdapter.php @@ -126,6 +126,25 @@ protected function getTitle() return $this->getObject()->getName(); } + protected function getHeadTitle() + { + $maxStringLen = 65; + + $type = $this->getType(); + $typeName = $this->getTranslator()->translate($type); + + $title = $this->getTitle(); + + //add "(Lehrplan)" etc + if ($type !== 'topic-folder') { + if (strlen($title) < ($maxStringLen-strlen($typeName))) { + $title .= ' (' . $typeName . ')'; + } + } + + return $title; + } + protected function getType() { return $this->getObject()->getTaxonomy()->getName(); diff --git a/src/module/Normalizer/src/Normalizer/Entity/Metadata.php b/src/module/Normalizer/src/Normalizer/Entity/Metadata.php index 030725ba..9b7c1e18 100644 --- a/src/module/Normalizer/src/Normalizer/Entity/Metadata.php +++ b/src/module/Normalizer/src/Normalizer/Entity/Metadata.php @@ -45,6 +45,12 @@ class Metadata extends AbstractOptions implements MetadataInterface * @var string */ protected $description; + + /** + * @var string + */ + protected $metaDescription; + /** * @var DateTime */ @@ -143,6 +149,22 @@ public function setDescription($description) $this->description = $description; } + /** + * @return string + */ + public function getMetaDescription() + { + return $this->metaDescription; + } + + /** + * @param string $metaDescription + */ + public function setMetaDescription($metaDescription) + { + $this->metaDescription = $metaDescription; + } + /** * @return array|\string[] */ diff --git a/src/module/Normalizer/src/Normalizer/Entity/MetadataInterface.php b/src/module/Normalizer/src/Normalizer/Entity/MetadataInterface.php index 8c506ec5..445f4055 100644 --- a/src/module/Normalizer/src/Normalizer/Entity/MetadataInterface.php +++ b/src/module/Normalizer/src/Normalizer/Entity/MetadataInterface.php @@ -42,6 +42,11 @@ public function getContext(); */ public function getDescription(); + /** + * @return string + */ + public function getMetaDescription(); + /** * @return DateTime */ diff --git a/src/module/Normalizer/src/Normalizer/Factory/NormalizeHelperFactory.php b/src/module/Normalizer/src/Normalizer/Factory/NormalizeHelperFactory.php index 1c09411d..7fc95a65 100644 --- a/src/module/Normalizer/src/Normalizer/Factory/NormalizeHelperFactory.php +++ b/src/module/Normalizer/src/Normalizer/Factory/NormalizeHelperFactory.php @@ -38,7 +38,10 @@ public function createService(ServiceLocatorInterface $serviceLocator) { $normalize = new Normalize(); $normalizer = $serviceLocator->getServiceLocator()->get('Normalizer\Normalizer'); + $instanceManager = $serviceLocator->getServiceLocator()->get('Instance\Manager\InstanceManager'); + $normalize->setNormalizer($normalizer); + $normalize->setInstanceManager($instanceManager); return $normalize; } diff --git a/src/module/Normalizer/src/Normalizer/Factory/NormalizerFactory.php b/src/module/Normalizer/src/Normalizer/Factory/NormalizerFactory.php index 1688b8b6..f1a82baa 100644 --- a/src/module/Normalizer/src/Normalizer/Factory/NormalizerFactory.php +++ b/src/module/Normalizer/src/Normalizer/Factory/NormalizerFactory.php @@ -37,6 +37,9 @@ class NormalizerFactory implements FactoryInterface public function createService(ServiceLocatorInterface $serviceLocator) { $storage = $serviceLocator->get('Normalizer\Storage\Storage'); - return new Normalizer($storage); + $translator = $serviceLocator->get('MvcTranslator'); + $normalizer = new Normalizer($storage); + $normalizer->setTranslator($translator); + return $normalizer; } } diff --git a/src/module/Normalizer/src/Normalizer/Normalizer.php b/src/module/Normalizer/src/Normalizer/Normalizer.php index 4cf6048f..5c2a3fcf 100644 --- a/src/module/Normalizer/src/Normalizer/Normalizer.php +++ b/src/module/Normalizer/src/Normalizer/Normalizer.php @@ -24,10 +24,12 @@ use Normalizer\Adapter\AdapterPluginManager; use Zend\Cache\Storage\StorageInterface; +use Zend\I18n\Translator\TranslatorAwareTrait; use Zend\ServiceManager\ServiceLocatorAwareTrait; class Normalizer implements NormalizerInterface { + use TranslatorAwareTrait; /** * @var Adapter\AdapterPluginManager @@ -39,6 +41,7 @@ class Normalizer implements NormalizerInterface */ protected $storage; + /** * @var array */ @@ -79,6 +82,7 @@ public function normalize($object) if ($object instanceof $class) { /* @var $adapterClass Adapter\AdapterInterface */ $adapter = $this->pluginManager->get($adapterClass); + $adapter->setTranslator($this->translator); $normalized = $adapter->normalize($object); // $this->storage->setItem($key, $normalized); return $normalized; diff --git a/src/module/Normalizer/src/Normalizer/View/Helper/Normalize.php b/src/module/Normalizer/src/Normalizer/View/Helper/Normalize.php index 6cb8454b..7ad8edb5 100644 --- a/src/module/Normalizer/src/Normalizer/View/Helper/Normalize.php +++ b/src/module/Normalizer/src/Normalizer/View/Helper/Normalize.php @@ -23,14 +23,19 @@ namespace Normalizer\View\Helper; use Common\Filter\PreviewFilter; +use Instance\Manager\InstanceManagerAwareTrait; +use Markdown\Service\OryRenderService; use Markdown\View\Helper\MarkdownHelper; +use Markdown\View\Helper\OryFormatHelper; use Normalizer\NormalizerAwareTrait; +use Ui\View\Helper\Brand; use Zend\View\Helper\AbstractHelper; use Zend\View\Helper\HeadMeta; use Zend\View\Helper\HeadTitle; class Normalize extends AbstractHelper { + use InstanceManagerAwareTrait; use NormalizerAwareTrait; public function __invoke($object = null) @@ -43,43 +48,151 @@ public function __invoke($object = null) public function headMeta($object) { - /* @var $meta HeadMeta */ - $meta = $this->getView()->plugin('headMeta'); + $meta = $this->getView()->plugin('headMeta'); $normalized = $this->normalize($object); - $title = $normalized->getTitle(); - $type = $normalized->getType(); - $metadata = $normalized->getMetadata(); - $keywords = $metadata->getKeywords(); - $robots = $metadata->getRobots(); - $preview = $this->toPreview($object); - $image = $this->getMetaImage($object); - $meta->setProperty('og:title', $title); - $meta->setProperty('og:image', $image); + + $type = $normalized->getType(); + $metadata = $normalized->getMetadata(); + + $keywords = $metadata->getKeywords(); + $robots = $metadata->getRobots(); + $meta->appendName('content_type', $type); - $meta->appendName('description', $preview); + $meta->appendName('description', $this->getMetaDescription($object)); $meta->appendName('keywords', implode(', ', $keywords)); $meta->appendName('robots', $robots); + $this->appendOpenSearchMeta($object); + $this->appendOpenGraphMeta($object); + $this->appendFacebookMeta($object); + return $this; } - public function getMetaImage($object) + private function appendOpenSearchMeta($object) + { + $lang = $this->getSubdomain(); + + if ($lang === 'de' || $lang === 'en') { + $this->getView()->headLink( + [ + 'rel' => 'search', + 'href' => '/opensearch.' . $lang . '.xml', + 'title' => 'Serlo (' . $lang . ')', + 'type' => 'application/opensearchdescription+xml', + ] + ); + } + } + + private function appendOpenGraphMeta($object) + { + $meta = $this->getMeta(); + + $meta->setProperty('og:title', $this->normalize($object)->getTitle()); + $meta->setProperty('og:type', 'website'); + $meta->setProperty('og:image', $this->getMetaImage($object)); + $meta->setProperty('og:description', $this->getMetaDescription($object)); + $meta->setProperty('og:site_name', $this->getView()->brand()->getBrand(true)); + } + + private function appendFacebookMeta($object) + { + $meta = $this->getMeta(); + + $meta->setProperty('fb:pages', '155020041197918'); + $meta->setProperty('fb:profile_id', '155020041197918'); + } + + + private function getMetaDescription($object) { - //TODO: Change path depending ob subject - return 'https://de.serlo.org/assets/images/meta_serlo.jpg'; + $metadata = $this->normalize($object)->getMetadata(); + return $this->renderPreview($metadata->getMetaDescription()); } - public function headTitle($object) + private function getMetaImage($object) + { + $fileName = 'serlo.jpg'; + + $subject = trim(strtolower(strip_tags( + $this->getView()->navigation('default_navigation') + ->menu() + ->setPartial('layout/navigation/partial/active-subject') + ->setOnlyActiveBranch(true) + ->setMinDepth(0) + ->setMaxDepth(0) + ->render() + ))); + + switch ($subject) { + case 'mathematik': + $fileName = 'de/mathematik.jpg'; + break; + + case 'angewandte nachhaltigkeit': + $fileName = 'de/angewandte-nachhaltigkeit.jpg'; + break; + + case 'biologie': + $fileName = 'de/biologie.jpg'; + break; + } + + return 'https://assets.serlo.org/meta/' . $fileName; + } + + private function getSubdomain() + { + return $this->getInstanceManager()->getInstanceFromRequest()->getSubdomain(); + } + + /** + * @return HeadMeta + */ + private function getMeta() + { + return $this->getView()->plugin('headMeta'); + } + + public function headTitle($object = null) { /* @var $headTitle HeadTitle */ $headTitle = $this->getView()->plugin('headTitle'); - $normalized = $this->normalize($object); - $title = $normalized->getTitle(); + if ($object == null) { + /** @var Brand $brand */ + $brand = $this->getView()->brand(); + $title = $brand->getBrand(true) . " – " . $brand->getSlogan(); + } elseif (is_string($object)) { + $title = $this->appendBrand($object); + } else { + $normalized = $this->normalize($object); + $title = $this->appendBrand($normalized->getMetadata()->getTitle()); + } $headTitle($title); - return $this; } + private function appendBrand($title) + { + /** @var Brand $brand */ + $brand = $this->getView()->brand(); + $maxStringLen = 65; + + //add "– lernen mit Serlo" + $titlePostfix = ' – ' . $brand->getHeadTitle(true); + if (strlen($title) < ($maxStringLen-strlen($titlePostfix))) { + return $title . $titlePostfix; + } + + $titlePostfixFallback = ' – ' . $brand->getBrand(true); + if (strlen($title) < ($maxStringLen-strlen($titlePostfixFallback))) { + return $title . $titlePostfixFallback; + } + + return $title; + } + public function possible($object) { try { @@ -114,12 +227,20 @@ public function toLastModified($object) public function toPreview($object) { - /* @var $markdown MarkdownHelper */ - $markdown = $this->getView()->plugin('markdown'); $normalized = $this->normalize($object); + $content = $normalized->getMetadata()->getDescription(); + return $this->renderPreview($content); + } + + private function renderPreview($string) + { + $isOryEditorFormat = $this->getView()->plugin('isOryEditorFormat'); + /** @var MarkdownHelper $renderer */ + $renderer = $isOryEditorFormat($string) + ? $this->getView()->plugin('oryRenderer') + : $this->getView()->plugin('markdown'); + $content = $renderer->toHtml($string); $filter = new PreviewFilter(152); - $content = $normalized->getContent(); - $content = $markdown->toHtml($content); $preview = $filter->filter($content); return $preview; } diff --git a/src/module/Ui/templates/entity/page/applet.twig b/src/module/Ui/templates/entity/page/applet.twig index 924c9318..4c7b8900 100644 --- a/src/module/Ui/templates/entity/page/applet.twig +++ b/src/module/Ui/templates/entity/page/applet.twig @@ -19,26 +19,9 @@ # @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 # @link https://github.com/serlo-org/athene2 for the canonical source repository #} -{% set metaDescriptionFallback = normalize().toPreview(entity) %} -{% set metaTitleFallback = normalize().toTitle(entity) ~ ' - ' ~ entity().findSubject(entity) ~ ' ' ~ (entity.getType().getName() | trans) %} -{% set metaDescription = entity.getCurrentRevision().get('meta_description') %} -{% set metaTitle = entity.getCurrentRevision().get('meta_title') %} - +{% do normalize().headTitle(entity) %} {% do normalize().headMeta(entity) %} -{% if metaDescription %} - {% do headMeta().setName('description', metaDescription) %} -{% else %} - {% do headMeta().setName('description', metaDescriptionFallback) %} -{% endif %} - -{% if metaTitle %} - {% do headTitle(metaTitle) %} - {% do headMeta().setProperty('og:title', metaTitle) %} -{% else %} - {% do headTitle(metaTitleFallback) %} -{% endif %} - {% set title = entity.getCurrentRevision().get('title') %} {% include 'entity/page/partials/placeholders' %}
diff --git a/src/module/Ui/templates/entity/page/article.twig b/src/module/Ui/templates/entity/page/article.twig index 31c3ffa6..97c54a21 100644 --- a/src/module/Ui/templates/entity/page/article.twig +++ b/src/module/Ui/templates/entity/page/article.twig @@ -19,26 +19,9 @@ # @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 # @link https://github.com/serlo-org/athene2 for the canonical source repository #} -{% set metaDescriptionFallback = normalize().toPreview(entity) %} -{% set metaTitleFallback = normalize().toTitle(entity) ~ ' - ' ~ entity().findSubject(entity) ~ ' ' ~ (entity.getType().getName() | trans) %} -{% set metaDescription = entity.getCurrentRevision().get('meta_description') %} -{% set metaTitle = entity.getCurrentRevision().get('meta_title') %} - +{% do normalize().headTitle(entity) %} {% do normalize().headMeta(entity) %} -{% if metaDescription %} - {% do headMeta().setName('description', metaDescription) %} -{% else %} - {% do headMeta().setName('description', metaDescriptionFallback) %} -{% endif %} - -{% if metaTitle %} - {% do headTitle(metaTitle) %} - {% do headMeta().setProperty('og:title', metaTitle) %} -{% else %} - {% do headTitle(metaTitleFallback) %} -{% endif %} - {% set title = entity.getCurrentRevision().get('title') %} {% include 'entity/page/partials/placeholders' %}
diff --git a/src/module/Ui/templates/entity/page/course-page.twig b/src/module/Ui/templates/entity/page/course-page.twig index 6b54881d..05dbe6ae 100644 --- a/src/module/Ui/templates/entity/page/course-page.twig +++ b/src/module/Ui/templates/entity/page/course-page.twig @@ -19,11 +19,10 @@ # @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 # @link https://github.com/serlo-org/athene2 for the canonical source repository #} -{% set title = entity.getCurrentRevision().get('title') %} {% set parent = entity.getParents('link').first() %} {% set title = normalize().toTitle(entity) %} -{% do headTitle(title ~ ' - ' ~ entity().findSubject(parent) ~ ' ' ~ (entity.getType().getName() | trans)) %} {% do normalize().headMeta(entity) %} +{% do normalize().headTitle(entity) %} {% set controls = include('entity/view/partials/actions/course/course-controls-wrapper', {'entity': entity, 'parent': parent}) %} {% do placeholder('controls').set(controls) %} @@ -35,4 +34,4 @@ {% set courseNav = include('entity/page/course-navigation', {'entity': parent, 'activePage': entity}) %} {% set temp = registry().add('rnav', courseNav) %} -{% set temp = registry().add('rnav-is-course', true) %} \ No newline at end of file +{% set temp = registry().add('rnav-is-course', true) %} diff --git a/src/module/Ui/templates/entity/page/course.twig b/src/module/Ui/templates/entity/page/course.twig index f19bd332..ac383770 100644 --- a/src/module/Ui/templates/entity/page/course.twig +++ b/src/module/Ui/templates/entity/page/course.twig @@ -19,9 +19,7 @@ # @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 # @link https://github.com/serlo-org/athene2 for the canonical source repository #} -{% do normalize().headMeta(entity) %} {% set title = normalize().toTitle(entity) %} -{% do headTitle(title ~ ' - ' ~ entity().findSubject(entity) ~ ' ' ~ (entity.getType().getName() | trans)) %} {% set title = entity.getCurrentRevision().get('title') %} {% include 'entity/page/partials/placeholders' %}
diff --git a/src/module/Ui/templates/entity/page/video.twig b/src/module/Ui/templates/entity/page/video.twig index 0cb2bc72..a9611d1d 100644 --- a/src/module/Ui/templates/entity/page/video.twig +++ b/src/module/Ui/templates/entity/page/video.twig @@ -21,7 +21,7 @@ #} {% do normalize().headMeta(entity) %} {% set title = normalize().toTitle(entity) %} -{% do headTitle(title ~ ' - ' ~ entity().findSubject(entity) ~ ' ' ~ (entity.getType().getName() | trans)) %} +{% do normalize().headTitle(entity) %} {% include 'entity/page/partials/placeholders' %}
-
+
    {% for link in types.get(type) %} -
    +
  • {% include 'taxonomy/term/entity/default' with {'entity': link} only %} -
  • + {% endfor %} -
+
{% endif %} @@ -129,7 +125,7 @@
{% endif %}
-
+
{% endfor %} diff --git a/src/public/opensearch.de.xml b/src/public/opensearch.de.xml new file mode 100644 index 00000000..89371fe7 --- /dev/null +++ b/src/public/opensearch.de.xml @@ -0,0 +1,32 @@ + + + Serlo (de) + +Serlo.org – Die freie Lernplattform + + UTF-8 + https://de.serlo.org/favicon.ico + + https://de.serlo.org/search + diff --git a/src/public/opensearch.en.xml b/src/public/opensearch.en.xml new file mode 100644 index 00000000..3aa27918 --- /dev/null +++ b/src/public/opensearch.en.xml @@ -0,0 +1,32 @@ + + + Serlo (en) + +Serlo.org – The Open Learning Platform + + UTF-8 + https://en.serlo.org/favicon.ico + + https://en.serlo.org/search + diff --git a/src/public/opensearch.xml b/src/public/opensearch.xml deleted file mode 100644 index 5b95feae..00000000 --- a/src/public/opensearch.xml +++ /dev/null @@ -1,10 +0,0 @@ - -Serlo (de) - -Serlo.org – Die freie Lernplattform - -UTF-8 -https://de.serlo.org/favicon.ico - -https://de.serlo.org/search -