feature: define redirects in a custom file (#7719) (#7945)

refs #7707

- be able to add a custom redirect file into the content folder
- define redirects as JSON format

The redirects feature is already present in the LTS branch.
I was not able to cherry-pick over, too many changes or conflicts.
Creating a PR to ensure 1. tests pass and 2. overview of code changes.
I had to add an example active theme to our test fixture utils, because otherwise Ghost will complain when forking Ghost.
This commit is contained in:
Katharina Irrgang 2017-02-06 15:32:40 +01:00 committed by GitHub
commit 4afb9a691c
11 changed files with 381 additions and 0 deletions

View File

@ -0,0 +1,22 @@
Copyright (c) 2013-2016 Ghost Foundation
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,16 @@
# Casper
The default theme for [Ghost](http://github.com/tryghost/ghost/).
To download, visit the [releases](https://github.com/TryGhost/Casper/releases) page.
## Copyright & License
Copyright (c) 2013-2016 Ghost Foundation - Released under the MIT License.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,41 @@
{{!< default}}
{{!-- The tag above means - insert everything in this file into the {body} of the default.hbs template --}}
{{!-- The big featured header --}}
{{!-- Everything inside the #author tags pulls data from the author --}}
{{#author}}
<header class="main-header author-head {{#if cover}}" style="background-image: url({{cover}}){{else}}no-cover{{/if}}">
<nav class="main-nav overlay clearfix">
{{#if @blog.logo}}<a class="blog-logo" href="{{@blog.url}}"><img src="{{@blog.logo}}" alt="{{@blog.title}}" /></a>{{/if}}
{{#if @blog.navigation}}
<a class="menu-button icon-menu" href="#"><span class="word">Menu</span></a>
{{/if}}
</nav>
</header>
<section class="author-profile inner">
{{#if image}}
<figure class="author-image">
<div class="img" style="background-image: url({{image}})"><span class="hidden">{{name}}'s Picture</span></div>
</figure>
{{/if}}
<h1 class="author-title">{{name}}</h1>
{{#if bio}}
<h2 class="author-bio">{{bio}}</h2>
{{/if}}
<div class="author-meta">
{{#if location}}<span class="author-location icon-location">{{location}}</span>{{/if}}
{{#if website}}<span class="author-link icon-link"><a href="{{website}}">{{website}}</a></span>{{/if}}
<span class="author-stats"><i class="icon-stats"></i> {{plural ../pagination.total empty='No posts' singular='% post' plural='% posts'}}</span>
</div>
</section>
{{/author}}
{{!-- The main content area on the homepage --}}
<main class="content" role="main">
{{!-- The tag below includes the post loop - partials/loop.hbs --}}
{{> "loop"}}
</main>

View File

@ -0,0 +1,54 @@
<!DOCTYPE html>
<html>
<head>
{{!-- Document Settings --}}
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
{{!-- Page Meta --}}
<title>{{meta_title}}</title>
<meta name="description" content="{{meta_description}}" />
{{!-- Mobile Meta --}}
<meta name="HandheldFriendly" content="True" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{{!-- Brand icon --}}
<link rel="shortcut icon" href="{{asset "favicon.ico"}}">
{{!-- Styles'n'Scripts --}}
<link rel="stylesheet" type="text/css" href="{{asset "css/screen.css"}}" />
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Merriweather:300,700,700italic,300italic|Open+Sans:700,400" />
{{!-- Ghost outputs important style and meta data with this tag --}}
{{ghost_head}}
</head>
<body class="{{body_class}} nav-closed">
{{!-- The blog navigation links --}}
{{navigation}}
<div class="site-wrapper">
{{!-- All the main content gets inserted here, index.hbs, post.hbs, etc --}}
{{{body}}}
{{!-- The tiny footer at the very bottom --}}
<footer class="site-footer clearfix">
<section class="copyright"><a href="{{@blog.url}}">{{@blog.title}}</a> &copy; {{date format="YYYY"}}</section>
<section class="poweredby">Proudly published with <a href="https://ghost.org">Ghost</a></section>
</footer>
</div>
{{!-- jQuery needs to come before `{{ghost_foot}}` so that jQuery can be used in code injection --}}
<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.0.min.js"></script>
{{!-- Ghost outputs important scripts and data with this tag --}}
{{ghost_foot}}
{{!-- Fitvids makes video embeds responsive and awesome --}}
<script type="text/javascript" src="{{asset "js/jquery.fitvids.js"}}"></script>
{{!-- The main JavaScript file for Casper --}}
<script type="text/javascript" src="{{asset "js/index.js"}}"></script>
</body>
</html>

View File

@ -0,0 +1,27 @@
{{!< default}}
{{!-- The tag above means - insert everything in this file into the {body} of the default.hbs template --}}
{{!-- The big featured header --}}
<header class="main-header {{#if @blog.cover}}" style="background-image: url({{@blog.cover}}){{else}}no-cover{{/if}}">
<nav class="main-nav overlay clearfix">
{{#if @blog.logo}}<a class="blog-logo" href="{{@blog.url}}"><img src="{{@blog.logo}}" alt="{{@blog.title}}" /></a>{{/if}}
{{#if @blog.navigation}}
<a class="menu-button icon-menu" href="#"><span class="word">Menu</span></a>
{{/if}}
</nav>
<div class="vertical">
<div class="main-header-content inner">
<h1 class="page-title">{{@blog.title}}</h1>
<h2 class="page-description">{{@blog.description}}</h2>
</div>
</div>
<a class="scroll-down icon-arrow-left" href="#content" data-offset="-45"><span class="hidden">Scroll Down</span></a>
</header>
{{!-- The main content area on the homepage --}}
<main id="content" class="content" role="main">
{{!-- The tag below includes the post loop - partials/loop.hbs --}}
{{> "loop"}}
</main>

View File

@ -0,0 +1,4 @@
{
"name": "Casper",
"version": "1.3.1"
}

View File

@ -0,0 +1,31 @@
{{!< default}}
{{!-- This is a page template. A page outputs content just like any other post, and has all the same
attributes by default, but you can also customise it to behave differently if you prefer. --}}
{{!-- Everything inside the #post tags pulls data from the page --}}
{{#post}}
<header class="main-header post-head {{#if image}}" style="background-image: url({{image}}){{else}}no-cover{{/if}}">
<nav class="main-nav {{#if image}}overlay{{/if}} clearfix">
{{#if @blog.logo}}<a class="blog-logo" href="{{@blog.url}}"><img src="{{@blog.logo}}" alt="{{@blog.title}}" /></a>{{/if}}
{{#if @blog.navigation}}
<a class="menu-button icon-menu" href="#"><span class="word">Menu</span></a>
{{/if}}
</nav>
</header>
<main class="content" role="main">
<article class="{{post_class}}">
<header class="post-header">
<h1 class="post-title">{{title}}</h1>
</header>
<section class="post-content">
{{content}}
</section>
</article>
</main>
{{/post}}

View File

@ -0,0 +1,25 @@
{{!-- Previous/next page links - only displayed on page 2+ --}}
<div class="extra-pagination inner">
{{pagination}}
</div>
{{!-- This is the post loop - each post will be output using this markup --}}
{{#foreach posts}}
<article class="{{post_class}}">
<header class="post-header">
<h2 class="post-title"><a href="{{url}}">{{title}}</a></h2>
</header>
<section class="post-excerpt">
<p>{{excerpt words="26"}} <a class="read-more" href="{{url}}">&raquo;</a></p>
</section>
<footer class="post-meta">
{{#if author.image}}<img class="author-thumb" src="{{author.image}}" alt="{{author.name}}" nopin="nopin" />{{/if}}
{{author}}
{{tags prefix=" on "}}
<time class="post-date" datetime="{{date format="YYYY-MM-DD"}}">{{date format="DD MMMM YYYY"}}</time>
</footer>
</article>
{{/foreach}}
{{!-- Previous/next page links - displayed on every page --}}
{{pagination}}

View File

@ -0,0 +1,17 @@
<div class="nav">
<h3 class="nav-title">Menu</h3>
<a href="#" class="nav-close">
<span class="hidden">Close</span>
</a>
<ul>
{{#foreach navigation}}
<li class="nav-{{slug}}{{#if current}} nav-current{{/if}}" role="presentation"><a href="{{url absolute="true"}}">{{label}}</a></li>
{{/foreach}}
</ul>
{{#if @labs.subscribers}}
<a class="subscribe-button" href="{{@blog.url}}/subscribe/">Subscribe</a>
{{else}}
<a class="subscribe-button icon-feed" href="{{@blog.url}}/rss/">Subscribe</a>
{{/if}}
</div>
<span class="nav-cover"></span>

View File

@ -0,0 +1,110 @@
{{!< default}}
{{!-- The comment above "< default" means - insert everything in this file into
the {{{body}}} of the default.hbs template, containing the blog header/footer. --}}
{{!-- Everything inside the #post tags pulls data from the post --}}
{{#post}}
<header class="main-header post-head {{#if image}}" style="background-image: url({{image}}){{else}}no-cover{{/if}}">
<nav class="main-nav {{#if image}}overlay{{/if}} clearfix">
{{#if @blog.logo}}<a class="blog-logo" href="{{@blog.url}}"><img src="{{@blog.logo}}" alt="{{@blog.title}}" /></a>{{/if}}
{{#if @blog.navigation}}
<a class="menu-button icon-menu" href="#"><span class="word">Menu</span></a>
{{/if}}
</nav>
</header>
<main class="content" role="main">
<article class="{{post_class}}">
<header class="post-header">
<h1 class="post-title">{{title}}</h1>
<section class="post-meta">
<time class="post-date" datetime="{{date format="YYYY-MM-DD"}}">{{date format="DD MMMM YYYY"}}</time> {{tags prefix=" on "}}
</section>
</header>
<section class="post-content">
{{content}}
</section>
<footer class="post-footer">
{{!-- Everything inside the #author tags pulls data from the author --}}
{{#author}}
{{#if image}}
<figure class="author-image">
<a class="img" href="{{url}}" style="background-image: url({{image}})"><span class="hidden">{{name}}'s Picture</span></a>
</figure>
{{/if}}
<section class="author">
<h4><a href="{{url}}">{{name}}</a></h4>
{{#if bio}}
<p>{{bio}}</p>
{{else}}
<p>Read <a href="{{url}}">more posts</a> by this author.</p>
{{/if}}
<div class="author-meta">
{{#if location}}<span class="author-location icon-location">{{location}}</span>{{/if}}
{{#if website}}<span class="author-link icon-link"><a href="{{website}}">{{website}}</a></span>{{/if}}
</div>
</section>
{{/author}}
<section class="share">
<h4>Share this post</h4>
<a class="icon-twitter" href="https://twitter.com/intent/tweet?text={{encode title}}&amp;url={{url absolute="true"}}"
onclick="window.open(this.href, 'twitter-share', 'width=550,height=235');return false;">
<span class="hidden">Twitter</span>
</a>
<a class="icon-facebook" href="https://www.facebook.com/sharer/sharer.php?u={{url absolute="true"}}"
onclick="window.open(this.href, 'facebook-share','width=580,height=296');return false;">
<span class="hidden">Facebook</span>
</a>
<a class="icon-google-plus" href="https://plus.google.com/share?url={{url absolute="true"}}"
onclick="window.open(this.href, 'google-plus-share', 'width=490,height=530');return false;">
<span class="hidden">Google+</span>
</a>
</section>
{{!-- Email subscribe form at the bottom of the page --}}
{{#if @labs.subscribers}}
<section class="gh-subscribe">
<h3 class="gh-subscribe-title">Subscribe to {{@blog.title}}</h3>
<p>Get the latest posts delivered right to your inbox.</p>
{{subscribe_form placeholder="Your email address"}}
<span class="gh-subscribe-rss">or subscribe <a href="http://cloud.feedly.com/#subscription/feed/{{@blog.url}}/rss/">via RSS</a> with Feedly!</span>
</section>
{{/if}}
</footer>
</article>
</main>
{{!-- Links to Previous/Next posts --}}
<aside class="read-next">
{{#next_post}}
<a class="read-next-story {{#if image}}" style="background-image: url({{image}}){{else}}no-cover{{/if}}" href="{{url}}">
<section class="post">
<h2>{{title}}</h2>
<p>{{excerpt words="19"}}&hellip;</p>
</section>
</a>
{{/next_post}}
{{#prev_post}}
<a class="read-next-story prev {{#if image}}" style="background-image: url({{image}}){{else}}no-cover{{/if}}" href="{{url}}">
<section class="post">
<h2>{{title}}</h2>
<p>{{excerpt words="19"}}&hellip;</p>
</section>
</a>
{{/prev_post}}
</aside>
{{/post}}

View File

@ -0,0 +1,34 @@
{{!< default}}
{{!-- The tag above means - insert everything in this file into the {body} of the default.hbs template --}}
{{!-- If we have a tag cover, display that - else blog cover - else nothing --}}
<header class="main-header tag-head {{#if tag.image}}" style="background-image: url({{tag.image}}){{else}}{{#if @blog.cover}}" style="background-image: url({{@blog.cover}}){{else}}no-cover{{/if}}{{/if}}">
<nav class="main-nav overlay clearfix">
{{#if @blog.logo}}<a class="blog-logo" href="{{@blog.url}}"><img src="{{@blog.logo}}" alt="{{@blog.title}}" /></a>{{/if}}
{{#if @blog.navigation}}
<a class="menu-button icon-menu" href="#"><span class="word">Menu</span></a>
{{/if}}
</nav>
<div class="vertical">
{{#tag}}
<div class="main-header-content inner">
<h1 class="page-title">{{name}}</h1>
<h2 class="page-description">
{{#if description}}
{{description}}
{{else}}
A {{../pagination.total}}-post collection
{{/if}}
</h2>
</div>
{{/tag}}
</div>
</header>
{{!-- The main content area on the homepage --}}
<main class="content" role="main">
{{!-- The tag below includes the post loop - partials/loop.hbs --}}
{{> "loop"}}
</main>