mirror of
https://github.com/standardebooks/web.git
synced 2025-07-14 02:21:55 -04:00
Add <link rel="canonical"> to some pages
This commit is contained in:
parent
f8b817c4e1
commit
7c8463d297
8 changed files with 128 additions and 82 deletions
|
@ -36,10 +36,6 @@ class Formatter{
|
||||||
return htmlspecialchars(trim($text ?? ''), ENT_QUOTES, 'utf-8');
|
return htmlspecialchars(trim($text ?? ''), ENT_QUOTES, 'utf-8');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function EscapeXhtmlQueryString(?string $text): string{
|
|
||||||
return str_replace('&', '&', trim($text ?? ''));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function EscapeXml(?string $text): string{
|
public static function EscapeXml(?string $text): string{
|
||||||
// Accepts a query string that has already been url-encoded. For example,
|
// Accepts a query string that has already been url-encoded. For example,
|
||||||
// ?foo=bar+baz&x=y
|
// ?foo=bar+baz&x=y
|
||||||
|
|
|
@ -11,6 +11,7 @@ $feedUrl = $feedUrl ?? null;
|
||||||
$feedTitle = $feedTitle ?? '';
|
$feedTitle = $feedTitle ?? '';
|
||||||
$isErrorPage = $isErrorPage ?? false;
|
$isErrorPage = $isErrorPage ?? false;
|
||||||
$downloadUrl = $downloadUrl ?? null;
|
$downloadUrl = $downloadUrl ?? null;
|
||||||
|
$canonicalUrl = $canonicalUrl ?? null;
|
||||||
|
|
||||||
// As of Sep 2022, all versions of Safari have a bug where if the page is served as XHTML,
|
// As of Sep 2022, all versions of Safari have a bug where if the page is served as XHTML,
|
||||||
// then <picture> elements download all <source>s instead of the first supported match.
|
// then <picture> elements download all <source>s instead of the first supported match.
|
||||||
|
@ -55,6 +56,9 @@ if(!$isXslt){
|
||||||
<? if($artwork){ ?>
|
<? if($artwork){ ?>
|
||||||
<link href="/css/artwork.css?version=<?= filemtime(WEB_ROOT . '/css/artwork.css') ?>" media="screen" rel="stylesheet" type="text/css"/>
|
<link href="/css/artwork.css?version=<?= filemtime(WEB_ROOT . '/css/artwork.css') ?>" media="screen" rel="stylesheet" type="text/css"/>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
<? if($canonicalUrl){ ?>
|
||||||
|
<link rel="canonical" href="<?= Formatter::EscapeHtml($canonicalUrl) ?>" />
|
||||||
|
<? } ?>
|
||||||
<link href="/apple-touch-icon-120x120.png" rel="apple-touch-icon" sizes="120x120"/>
|
<link href="/apple-touch-icon-120x120.png" rel="apple-touch-icon" sizes="120x120"/>
|
||||||
<link href="/apple-touch-icon-152x152.png" rel="apple-touch-icon" sizes="152x152"/>
|
<link href="/apple-touch-icon-152x152.png" rel="apple-touch-icon" sizes="152x152"/>
|
||||||
<link href="/apple-touch-icon.png" rel="apple-touch-icon" sizes="180x180"/>
|
<link href="/apple-touch-icon.png" rel="apple-touch-icon" sizes="180x180"/>
|
||||||
|
@ -66,9 +70,9 @@ if(!$isXslt){
|
||||||
<link rel="alternate" type="application/atom+xml;profile=opds-catalog;kind=acquisition" title="Standard Ebooks - New Releases" href="https://standardebooks.org/feeds/opds/new-releases"/>
|
<link rel="alternate" type="application/atom+xml;profile=opds-catalog;kind=acquisition" title="Standard Ebooks - New Releases" href="https://standardebooks.org/feeds/opds/new-releases"/>
|
||||||
<link rel="alternate" type="application/rss+xml" title="Standard Ebooks - New Releases" href="https://standardebooks.org/feeds/rss/new-releases"/>
|
<link rel="alternate" type="application/rss+xml" title="Standard Ebooks - New Releases" href="https://standardebooks.org/feeds/rss/new-releases"/>
|
||||||
<? }else{ ?>
|
<? }else{ ?>
|
||||||
<link rel="alternate" type="application/atom+xml" title="<?= Formatter::EscapeHtml($feedTitle) ?>" href="/feeds/atom<?= $feedUrl ?>"/>
|
<link rel="alternate" type="application/atom+xml" title="<?= Formatter::EscapeHtml($feedTitle) ?>" href="/feeds/atom<?= Formatter::EscapeHtml($feedUrl) ?>"/>
|
||||||
<link rel="alternate" type="application/atom+xml;profile=opds-catalog;kind=acquisition" title="<?= Formatter::EscapeHtml($feedTitle) ?>" href="/feeds/opds<?= $feedUrl ?>"/>
|
<link rel="alternate" type="application/atom+xml;profile=opds-catalog;kind=acquisition" title="<?= Formatter::EscapeHtml($feedTitle) ?>" href="/feeds/opds<?= Formatter::EscapeHtml($feedUrl) ?>"/>
|
||||||
<link rel="alternate" type="application/rss+xml" title="<?= Formatter::EscapeHtml($feedTitle) ?>" href="/feeds/rss<?= $feedUrl ?>"/>
|
<link rel="alternate" type="application/rss+xml" title="<?= Formatter::EscapeHtml($feedTitle) ?>" href="/feeds/rss<?= Formatter::EscapeHtml($feedUrl) ?>"/>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<link rel="search" href="/ebooks" type="application/xhtml+xml; charset=utf-8"/>
|
<link rel="search" href="/ebooks" type="application/xhtml+xml; charset=utf-8"/>
|
||||||
<link rel="search" href="/ebooks/opensearch" type="application/opensearchdescription+xml; charset=utf-8"/>
|
<link rel="search" href="/ebooks/opensearch" type="application/opensearchdescription+xml; charset=utf-8"/>
|
||||||
|
|
|
@ -97,8 +97,23 @@ try{
|
||||||
$queryStringParams['per-page'] = $perPage;
|
$queryStringParams['per-page'] = $perPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($page > 1){
|
||||||
|
$queryStringParams['page'] = $page;
|
||||||
|
}
|
||||||
|
|
||||||
|
ksort($queryStringParams);
|
||||||
|
|
||||||
$queryString = http_build_query($queryStringParams);
|
$queryString = http_build_query($queryStringParams);
|
||||||
|
|
||||||
|
unset($queryStringParams['page']);
|
||||||
|
$queryStringWithoutPage = http_build_query($queryStringParams);
|
||||||
|
|
||||||
|
$canonicalUrl = SITE_URL . '/artworks';
|
||||||
|
|
||||||
|
if($queryString != ''){
|
||||||
|
$canonicalUrl .= '?' . $queryString;
|
||||||
|
}
|
||||||
|
|
||||||
$pages = ceil($totalArtworkCount / $perPage);
|
$pages = ceil($totalArtworkCount / $perPage);
|
||||||
if($pages > 0 && $page > $pages){
|
if($pages > 0 && $page > $pages){
|
||||||
throw new Exceptions\PageOutOfBoundsException();
|
throw new Exceptions\PageOutOfBoundsException();
|
||||||
|
@ -106,14 +121,14 @@ try{
|
||||||
}
|
}
|
||||||
catch(Exceptions\PageOutOfBoundsException){
|
catch(Exceptions\PageOutOfBoundsException){
|
||||||
$url = '/artworks?page=' . $pages;
|
$url = '/artworks?page=' . $pages;
|
||||||
if($queryString != ''){
|
if($queryStringWithoutPage != ''){
|
||||||
$url .= '&' . $queryString;
|
$url .= '&' . $queryStringWithoutPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
header('Location: ' . $url);
|
header('Location: ' . $url);
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
?><?= Template::Header(['title' => $pageTitle, 'artwork' => true, 'description' => $pageDescription]) ?>
|
?><?= Template::Header(['title' => $pageTitle, 'artwork' => true, 'description' => $pageDescription, 'canonicalUrl' => $canonicalUrl]) ?>
|
||||||
<main class="artworks">
|
<main class="artworks">
|
||||||
<section class="narrow">
|
<section class="narrow">
|
||||||
<h1>Browse U.S. Public Domain Artwork</h1>
|
<h1>Browse U.S. Public Domain Artwork</h1>
|
||||||
|
@ -167,13 +182,13 @@ catch(Exceptions\PageOutOfBoundsException){
|
||||||
|
|
||||||
<? if($totalArtworkCount > 0){ ?>
|
<? if($totalArtworkCount > 0){ ?>
|
||||||
<nav class="pagination">
|
<nav class="pagination">
|
||||||
<a<? if($page > 1){ ?> href="/artworks?page=<?= $page - 1 ?><? if($queryString != ''){ ?><?= Formatter::EscapeXhtmlQueryString('&' . $queryString) ?><? } ?>" rel="prev"<? }else{ ?> aria-disabled="true"<? } ?>>Back</a>
|
<a<? if($page > 1){ ?> href="/artworks?page=<?= $page - 1 ?><? if($queryStringWithoutPage != ''){ ?>&<?= Formatter::EscapeHtml($queryStringWithoutPage) ?><? } ?>" rel="prev"<? }else{ ?> aria-disabled="true"<? } ?>>Back</a>
|
||||||
<ol>
|
<ol>
|
||||||
<? for($i = 1; $i < $pages + 1; $i++){ ?>
|
<? for($i = 1; $i < $pages + 1; $i++){ ?>
|
||||||
<li<? if($page == $i){ ?> class="highlighted"<? } ?>><a href="/artworks?page=<?= $i ?><? if($queryString != ''){ ?><?= Formatter::EscapeXhtmlQueryString('&' . $queryString) ?><? } ?>"><?= $i ?></a></li>
|
<li<? if($page == $i){ ?> class="highlighted"<? } ?>><a href="/artworks?page=<?= $i ?><? if($queryStringWithoutPage != ''){ ?>&<?= Formatter::EscapeHtml($queryStringWithoutPage) ?><? } ?>"><?= $i ?></a></li>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</ol>
|
</ol>
|
||||||
<a<? if($page < ceil($totalArtworkCount / $perPage)){ ?> href="/artworks?page=<?= $page + 1 ?><? if($queryString != ''){ ?><?= Formatter::EscapeXhtmlQueryString('&' . $queryString) ?><? } ?>" rel="next"<? }else{ ?> aria-disabled="true"<? } ?>>Next</a>
|
<a<? if($page < ceil($totalArtworkCount / $perPage)){ ?> href="/artworks?page=<?= $page + 1 ?><? if($queryStringWithoutPage != ''){ ?>&<?= Formatter::EscapeHtml($queryStringWithoutPage) ?><? } ?>" rel="next"<? }else{ ?> aria-disabled="true"<? } ?>>Next</a>
|
||||||
</nav>
|
</nav>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -28,7 +28,7 @@ try{
|
||||||
$pageDescription = 'A list of free ebooks in the ' . Formatter::EscapeHtml($collectionName) . ' ' . $collectionType;
|
$pageDescription = 'A list of free ebooks in the ' . Formatter::EscapeHtml($collectionName) . ' ' . $collectionType;
|
||||||
$pageHeader = 'Free Ebooks in the ' . Formatter::EscapeHtml($collectionName) . ' ' . ucfirst($collectionType);
|
$pageHeader = 'Free Ebooks in the ' . Formatter::EscapeHtml($collectionName) . ' ' . ucfirst($collectionType);
|
||||||
|
|
||||||
$feedUrl = '/collections/' . Formatter::EscapeHtml($collection);
|
$feedUrl = '/collections/' . $collection;
|
||||||
$feedTitle = 'Standard Ebooks - Ebooks in the ' . Formatter::EscapeHtml($collectionName) . ' ' . $collectionType;
|
$feedTitle = 'Standard Ebooks - Ebooks in the ' . Formatter::EscapeHtml($collectionName) . ' ' . $collectionType;
|
||||||
}
|
}
|
||||||
catch(Exceptions\CollectionNotFoundException){
|
catch(Exceptions\CollectionNotFoundException){
|
||||||
|
|
|
@ -19,17 +19,17 @@ try{
|
||||||
}
|
}
|
||||||
|
|
||||||
$author = strip_tags($ebooks[0]->AuthorsHtml);
|
$author = strip_tags($ebooks[0]->AuthorsHtml);
|
||||||
$authorUrl = Formatter::EscapeHtml($ebooks[0]->AuthorsUrl);
|
$authorUrl = $ebooks[0]->AuthorsUrl;
|
||||||
}
|
}
|
||||||
catch(Exceptions\AuthorNotFoundException){
|
catch(Exceptions\AuthorNotFoundException){
|
||||||
Template::Emit404();
|
Template::Emit404();
|
||||||
}
|
}
|
||||||
?><?= Template::Header(['title' => 'Ebooks by ' . $author, 'feedUrl' => str_replace('/ebooks/', '/authors/', $authorUrl), 'feedTitle' => 'Standard Ebooks - Ebooks by ' . $author, 'highlight' => 'ebooks', 'description' => 'All of the Standard Ebooks ebooks by ' . $author]) ?>
|
?><?= Template::Header(['title' => 'Ebooks by ' . $author, 'feedUrl' => str_replace('/ebooks/', '/authors/', $authorUrl), 'feedTitle' => 'Standard Ebooks - Ebooks by ' . $author, 'highlight' => 'ebooks', 'description' => 'All of the Standard Ebooks ebooks by ' . $author, 'canonicalUrl' => SITE_URL . $authorUrl]) ?>
|
||||||
<main class="ebooks">
|
<main class="ebooks">
|
||||||
<h1 class="is-collection">Ebooks by <?= $ebooks[0]->AuthorsHtml ?></h1>
|
<h1 class="is-collection">Ebooks by <?= $ebooks[0]->AuthorsHtml ?></h1>
|
||||||
<p class="ebooks-toolbar">
|
<p class="ebooks-toolbar">
|
||||||
<a class="button" href="<?= $authorUrl ?>/downloads">Download collection</a>
|
<a class="button" href="<?= Formatter::EscapeHtml($authorUrl) ?>/downloads">Download collection</a>
|
||||||
<a class="button" href="<?= $authorUrl ?>/feeds">Feeds for this author</a>
|
<a class="button" href="<?= Formatter::EscapeHtml($authorUrl) ?>/feeds">Feeds for this author</a>
|
||||||
</p>
|
</p>
|
||||||
<?= Template::EbookGrid(['ebooks' => $ebooks, 'view' => VIEW_GRID]) ?>
|
<?= Template::EbookGrid(['ebooks' => $ebooks, 'view' => VIEW_GRID]) ?>
|
||||||
<p class="feeds-alert">We also have <a href="/bulk-downloads">bulk ebook downloads</a> and a <a href="/collections">list of collections</a> available, as well as <a href="/feeds">ebook catalog feeds</a> for use directly in your ereader app or RSS reader.</p>
|
<p class="feeds-alert">We also have <a href="/bulk-downloads">bulk ebook downloads</a> and a <a href="/collections">list of collections</a> available, as well as <a href="/feeds">ebook catalog feeds</a> for use directly in your ereader app or RSS reader.</p>
|
||||||
|
|
|
@ -107,7 +107,7 @@ catch(Exceptions\SeeOtherEbookException $ex){
|
||||||
catch(Exceptions\EbookNotFoundException){
|
catch(Exceptions\EbookNotFoundException){
|
||||||
Template::Emit404();
|
Template::Emit404();
|
||||||
}
|
}
|
||||||
?><?= Template::Header(['title' => strip_tags($ebook->TitleWithCreditsHtml) . ' - Free ebook download', 'ogType' => 'book', 'coverUrl' => $ebook->DistCoverUrl, 'highlight' => 'ebooks', 'description' => 'Free epub ebook download of the Standard Ebooks edition of ' . $ebook->Title . ': ' . $ebook->Description]) ?>
|
?><?= Template::Header(['title' => strip_tags($ebook->TitleWithCreditsHtml) . ' - Free ebook download', 'ogType' => 'book', 'coverUrl' => $ebook->DistCoverUrl, 'highlight' => 'ebooks', 'description' => 'Free epub ebook download of the Standard Ebooks edition of ' . $ebook->Title . ': ' . $ebook->Description, 'canonicalUrl' => SITE_URL . $ebook->Url]) ?>
|
||||||
<main>
|
<main>
|
||||||
<article class="ebook" typeof="schema:Book" about="<?= $ebook->Url ?>">
|
<article class="ebook" typeof="schema:Book" about="<?= $ebook->Url ?>">
|
||||||
<meta property="schema:description" content="<?= Formatter::EscapeHtml($ebook->Description) ?>"/>
|
<meta property="schema:description" content="<?= Formatter::EscapeHtml($ebook->Description) ?>"/>
|
||||||
|
|
|
@ -8,7 +8,9 @@ $tags = HttpInput::GetArray('tags') ?? [];
|
||||||
$view = HttpInput::Str(GET, 'view');
|
$view = HttpInput::Str(GET, 'view');
|
||||||
$sort = EbookSort::tryFrom(HttpInput::Str(GET, 'sort') ?? '');
|
$sort = EbookSort::tryFrom(HttpInput::Str(GET, 'sort') ?? '');
|
||||||
$queryString = '';
|
$queryString = '';
|
||||||
|
$queryStringParams = [];
|
||||||
|
|
||||||
|
try{
|
||||||
if($page <= 0){
|
if($page <= 0){
|
||||||
$page = 1;
|
$page = 1;
|
||||||
}
|
}
|
||||||
|
@ -42,6 +44,7 @@ $pages = ceil(sizeof($ebooks) / $perPage);
|
||||||
$totalEbooks = sizeof($ebooks);
|
$totalEbooks = sizeof($ebooks);
|
||||||
$ebooks = array_slice($ebooks, ($page - 1) * $perPage, $perPage);
|
$ebooks = array_slice($ebooks, ($page - 1) * $perPage, $perPage);
|
||||||
|
|
||||||
|
|
||||||
if($page > 1){
|
if($page > 1){
|
||||||
$pageTitle .= ', page ' . $page;
|
$pageTitle .= ', page ' . $page;
|
||||||
}
|
}
|
||||||
|
@ -49,28 +52,56 @@ if($page > 1){
|
||||||
$pageDescription = 'Page ' . $page . ' of the Standard Ebooks free ebook library';
|
$pageDescription = 'Page ' . $page . ' of the Standard Ebooks free ebook library';
|
||||||
|
|
||||||
if($query != ''){
|
if($query != ''){
|
||||||
$queryString .= '&query=' . urlencode($query);
|
$queryStringParams['query'] = $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($tags as $tag){
|
if(sizeof($tags) > 0){
|
||||||
$queryString .= '&tags[]=' . urlencode($tag);
|
$queryStringParams['tags'] = $tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($view !== null){
|
if($view !== null){
|
||||||
$queryString .= '&view=' . urlencode($view);
|
$queryStringParams['view'] = $view;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($sort !== null){
|
if($sort !== null){
|
||||||
$queryString .= '&sort=' . urlencode($sort->value);
|
$queryStringParams['sort'] = $sort->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($perPage !== EBOOKS_PER_PAGE){
|
if($perPage !== EBOOKS_PER_PAGE){
|
||||||
$queryString .= '&per-page=' . urlencode((string)$perPage);
|
$queryStringParams['per-page'] = $perPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
$queryString = preg_replace('/^&/ius', '', $queryString);
|
if($page > 1){
|
||||||
|
$queryStringParams['page'] = $page;
|
||||||
|
}
|
||||||
|
|
||||||
?><?= Template::Header(['title' => $pageTitle, 'highlight' => 'ebooks', 'description' => $pageDescription]) ?>
|
ksort($queryStringParams);
|
||||||
|
|
||||||
|
$queryString = http_build_query($queryStringParams);
|
||||||
|
|
||||||
|
unset($queryStringParams['page']);
|
||||||
|
$queryStringWithoutPage = http_build_query($queryStringParams);
|
||||||
|
|
||||||
|
$canonicalUrl = SITE_URL . '/ebooks';
|
||||||
|
|
||||||
|
if($queryString != ''){
|
||||||
|
$canonicalUrl .= '?' . $queryString;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($pages > 0 && $page > $pages){
|
||||||
|
throw new Exceptions\PageOutOfBoundsException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exceptions\PageOutOfBoundsException){
|
||||||
|
$url = '/ebooks?page=' . $pages;
|
||||||
|
if($queryStringWithoutPage != ''){
|
||||||
|
$url .= '&' . $queryStringWithoutPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
header('Location: ' . $url);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
?><?= Template::Header(['title' => $pageTitle, 'highlight' => 'ebooks', 'description' => $pageDescription, 'canonicalUrl' => $canonicalUrl]) ?>
|
||||||
<main class="ebooks">
|
<main class="ebooks">
|
||||||
<h1><?= $pageHeader ?></h1>
|
<h1><?= $pageHeader ?></h1>
|
||||||
<?= Template::DonationCounter() ?>
|
<?= Template::DonationCounter() ?>
|
||||||
|
@ -86,13 +117,13 @@ $queryString = preg_replace('/^&/ius', '', $queryString);
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? if(sizeof($ebooks) > 0){ ?>
|
<? if(sizeof($ebooks) > 0){ ?>
|
||||||
<nav class="pagination">
|
<nav class="pagination">
|
||||||
<a<? if($page > 1){ ?> href="/ebooks?page=<?= $page - 1 ?><? if($queryString != ''){ ?>&<?= $queryString ?><? } ?>" rel="prev"<? }else{ ?> aria-disabled="true"<? } ?>>Back</a>
|
<a<? if($page > 1){ ?> href="/ebooks?page=<?= $page - 1 ?><? if($queryStringWithoutPage != ''){ ?>&<?= Formatter::EscapeHtml($queryStringWithoutPage) ?><? } ?>" rel="prev"<? }else{ ?> aria-disabled="true"<? } ?>>Back</a>
|
||||||
<ol>
|
<ol>
|
||||||
<? for($i = 1; $i < $pages + 1; $i++){ ?>
|
<? for($i = 1; $i < $pages + 1; $i++){ ?>
|
||||||
<li<? if($page == $i){ ?> class="highlighted"<? } ?>><a href="/ebooks?page=<?= $i ?><? if($queryString != ''){ ?>&<?= $queryString ?><? } ?>"><?= $i ?></a></li>
|
<li<? if($page == $i){ ?> class="highlighted"<? } ?>><a href="/ebooks?page=<?= $i ?><? if($queryStringWithoutPage != ''){ ?>&<?= Formatter::EscapeHtml($queryStringWithoutPage) ?><? } ?>"><?= $i ?></a></li>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</ol>
|
</ol>
|
||||||
<a<? if($page < ceil($totalEbooks / $perPage)){ ?> href="/ebooks?page=<?= $page + 1 ?><? if($queryString != ''){ ?>&<?= $queryString ?><? } ?>" rel="next"<? }else{ ?> aria-disabled="true"<? } ?>>Next</a>
|
<a<? if($page < ceil($totalEbooks / $perPage)){ ?> href="/ebooks?page=<?= $page + 1 ?><? if($queryStringWithoutPage != ''){ ?>&<?= Formatter::EscapeHtml($queryStringWithoutPage) ?><? } ?>" rel="next"<? }else{ ?> aria-disabled="true"<? } ?>>Next</a>
|
||||||
</nav>
|
</nav>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['description' => 'Free and liberated ebooks, carefully produced for the true book lover. Download free ebooks with professional-quality formatting and typography, in formats compatible with your ereader.']) ?>
|
<?= Template::Header(['description' => 'Free and liberated ebooks, carefully produced for the true book lover. Download free ebooks with professional-quality formatting and typography, in formats compatible with your ereader.', 'canonicalUrl' => SITE_URL]) ?>
|
||||||
<main class="front-page">
|
<main class="front-page">
|
||||||
<h1>Free and liberated ebooks,<br/> carefully produced for the true book lover.</h1>
|
<h1>Free and liberated ebooks,<br/> carefully produced for the true book lover.</h1>
|
||||||
<picture>
|
<picture>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue