Skip to content
This repository has been archived by the owner on May 25, 2020. It is now read-only.

Seo improvements #678

Merged
merged 12 commits into from
Nov 13, 2018
4 changes: 2 additions & 2 deletions src/config/autoload/local.php.dist
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ return [
'slogan' => 'Freie Bildung.',
'description' => 'Serlo ist eine kostenlose Plattform mit freien Lernmaterialien, die alle mitgestalten können.',
'logo' => '<span class="serlo-logo">V</span>',
'head_title' => 'Serlo.org'
'head_title' => 'lernen mit Serlo!'
],
'english' => [
'name' => '<div class="serlo-brand">Serlo</div>',
'slogan' => 'Open Education.',
'description' => 'Serlo is a free service with open educational resources, which anyone can contribute to.',
'logo' => '<span class="serlo-logo">V</span>',
'head_title' => 'Serlo.org'
'head_title' => 'lernen mit Serlo!'
]
]
],
Expand Down
4 changes: 2 additions & 2 deletions src/config/autoload/serlo.config.local.php.dist
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ return [
'slogan' => 'Die freie Lernplattform',
'description' => 'Serlo ist eine kostenlose Plattform mit freien Lernmaterialien, die alle mitgestalten können.',
'logo' => '<span class="serlo-logo">V</span>',
'head_title' => 'Serlo.org'
'head_title' => 'lernen mit Serlo!'
],
'english' => [
'name' => '<div class="serlo-brand">Serlo</div>',
'slogan' => 'The Open Learning Platform',
'description' => 'Serlo is a free service with open educational resources, which anyone can contribute to.',
'logo' => '<span class="serlo-logo">V</span>',
'head_title' => 'Serlo.org'
'head_title' => 'lernen mit Serlo!'
]
]
],
Expand Down
25 changes: 25 additions & 0 deletions src/module/Normalizer/src/Normalizer/Adapter/AbstractAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,18 @@
use Normalizer\Entity\Normalized;
use DateTime;
use Normalizer\Exception\RuntimeException;
use Zend\I18n\Translator\TranslatorInterface;
inyono marked this conversation as resolved.
Show resolved Hide resolved
use Zend\Mvc\I18n\Translator;

abstract class AbstractAdapter implements AdapterInterface
{
protected $object;

/**
* @var TranslatorInterface
*/
protected $translator;

public function getObject()
{
return $this->object;
Expand All @@ -26,6 +33,16 @@ public function setObject($object)
$this->object = $object;
}

public function getTranslator()
{
return $this->translator;
}

public function setTranslator($translator)
{
$this->translator = $translator;
}

public function normalize($object)
{
if (!$this->isValid($object)) {
Expand All @@ -46,6 +63,7 @@ public function normalize($object)
'routeParams' => $this->getRouteParams(),
'id' => $this->getId(),
'metadata' => [
'title' => $this->getHeadTitle(),
'creationDate' => $this->getCreationDate() ? $this->getCreationDate() : new DateTime(),
'description' => $this->getDescription(),
'keywords' => $this->getKeywords(),
Expand Down Expand Up @@ -122,4 +140,11 @@ abstract protected function getType();
* @return boolean
*/
abstract protected function isTrashed();

/**
* @return string
*/
protected function getHeadTitle() {
return $this->getTitle();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
namespace Normalizer\Adapter;

use Normalizer\Entity\NormalizedInterface;
use Zend\I18n\Translator\TranslatorInterface;
inyono marked this conversation as resolved.
Show resolved Hide resolved

interface AdapterInterface
{
Expand All @@ -18,6 +19,12 @@ interface AdapterInterface
*/
public function normalize($object);

/**
* @param TranslatorInterface $translator
* @return void
*/
public function setTranslator($translator);

/**
* @param object $object
* @return true
Expand Down
29 changes: 29 additions & 0 deletions src/module/Normalizer/src/Normalizer/Adapter/EntityAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,33 @@ 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->getObject()->getCurrentRevision()->get('meta_title') ?: $titleFallback;

if ($type === 'course-page') {
$parent = $this->getObject()->getParents('link')->first();
$normalizedParent = $this->normalize($parent);
$parentTitleFallback = $normalizedParent->getTitle();

$parentTitle = $parent->getCurrentRevision()->get('title') ?: $parentTitleFallback;
$title = $parentTitle . " | " .$title;
}

//add "(Kurs)" etc
if ($type !== 'article') {
if( strlen($title) < ($maxStringLen-strlen($typeName)) ){
$title .= ' (' . $typeName . ')';
}
}

return $title;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class NormalizerFactory implements FactoryInterface
public function createService(ServiceLocatorInterface $serviceLocator)
{
$storage = $serviceLocator->get('Normalizer\Storage\Storage');
return new Normalizer($storage);
$translator = $serviceLocator->get('MvcTranslator');
return new Normalizer($storage, $translator);
}
}
10 changes: 9 additions & 1 deletion src/module/Normalizer/src/Normalizer/Normalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

use Normalizer\Adapter\AdapterPluginManager;
use Zend\Cache\Storage\StorageInterface;
use Zend\I18n\Translator\TranslatorInterface;
inyono marked this conversation as resolved.
Show resolved Hide resolved
use Zend\ServiceManager\ServiceLocatorAwareTrait;

class Normalizer implements NormalizerInterface
Expand All @@ -25,6 +26,11 @@ class Normalizer implements NormalizerInterface
*/
protected $storage;

/**
* @var TranslatorInterface
*/
protected $translator;

/**
* @var array
*/
Expand All @@ -40,13 +46,14 @@ class Normalizer implements NormalizerInterface
'User\Entity\UserInterface' => 'Normalizer\Adapter\UserAdapter',
];

public function __construct(StorageInterface $storage, AdapterPluginManager $pluginManager = null)
public function __construct(StorageInterface $storage, TranslatorInterface $translator, AdapterPluginManager $pluginManager = null)
{
if (!$pluginManager) {
$pluginManager = new AdapterPluginManager();
}
$this->pluginManager = $pluginManager;
$this->storage = $storage;
$this->translator = $translator;
}

public function normalize($object)
Expand All @@ -65,6 +72,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;
Expand Down
86 changes: 78 additions & 8 deletions src/module/Normalizer/src/Normalizer/View/Helper/Normalize.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Common\Filter\PreviewFilter;
use Markdown\View\Helper\MarkdownHelper;
use Normalizer\NormalizerAwareTrait;
use Ui\View\Helper\Brand;
use Zend\View\Helper\AbstractHelper;
use Zend\View\Helper\HeadMeta;
use Zend\View\Helper\HeadTitle;
Expand All @@ -19,6 +20,8 @@ class Normalize extends AbstractHelper
{
use NormalizerAwareTrait;

private static $maxStringLen = 65;

public function __invoke($object = null)
{
if ($object === null) {
Expand All @@ -39,33 +42,100 @@ public function headMeta($object)
$robots = $metadata->getRobots();
$preview = $this->toPreview($object);
$image = $this->getMetaImage($object);
$meta->setProperty('og:title', $title);
$meta->setProperty('og:image', $image);
$site_name = $this->getView()->brand()->getBrand(true);

$meta->appendName('content_type', $type);
$meta->appendName('description', $preview);
$meta->appendName('keywords', implode(', ', $keywords));
$meta->appendName('robots', $robots);
$meta->setProperty('og:title', $title);
$meta->setProperty('og:type', 'website');
$meta->setProperty('og:image', $image);
$meta->setProperty('og:description', $preview);
$meta->setProperty('og:site_name', $site_name);
$meta->setProperty('fb:pages', '155020041197918');
$meta->setProperty('fb:profile_id', '155020041197918');
$this->getView()->headLink(['rel' => 'search', 'href' => '/opensearch.xml', 'title' => 'Serlo (de)','type' => 'application/opensearchdescription+xml']);

return $this;
}


public function getMetaImage($object)
{
//TODO: Change path depending ob subject
return 'https://de.serlo.org/assets/images/meta_serlo.jpg';
$fileName = 'meta_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':
case 'math':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO: either we add English versions of the images or remove the behaviour for en.serlo.org for now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Knorrke: I removed the handling for subjects on en.serlo.org for now (i.e. the fallback image is used instead). Are you fine with that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's fine I guess

$fileName = 'meta_serlo_mathe.png';
break;

case 'angewandte nachhaltigkeit':
case 'applied sustainability':
$fileName = 'meta_serlo_nachhaltigkeit.png';
break;

case 'biologie':
case 'biology':
$fileName = 'meta_serlo_bio.png';
break;

default:
break;
}
return 'https://de.serlo.org/assets/images/'.$fileName;
inyono marked this conversation as resolved.
Show resolved Hide resolved
}

public function headTitle($object)
public function headTitle($object = null)
{
/* @var $headTitle HeadTitle */
$headTitle = $this->getView()->plugin('headTitle');
$normalized = $this->normalize($object);
$title = $normalized->getTitle();
$headTitle($title);

$title='';
if($object == null) {
/** @var Brand $brand */
$brand = $this->getView()->brand();
$title = $brand->getBrand(true) . " – " . $brand->getSlogan();
} else if(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 {
Expand Down
19 changes: 1 addition & 18 deletions src/module/Ui/templates/entity/page/article.twig
Original file line number Diff line number Diff line change
@@ -1,23 +1,6 @@
{% 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' %}
<div itemscope itemtype="http://schema.org/Article">
Expand Down
5 changes: 2 additions & 3 deletions src/module/Ui/templates/entity/page/course-page.twig
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
{% 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) %}
Expand All @@ -14,4 +13,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) %}
{% set temp = registry().add('rnav-is-course', true) %}
2 changes: 1 addition & 1 deletion src/module/Ui/templates/entity/page/course.twig
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% do normalize().headMeta(entity) %}
{% do normalize().headTitle(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' %}
<div itemscope itemtype="http://schema.org/Article">
Expand Down
Loading