I'm trying to create dynamic pages based on a database that grows by the minute. Therefor it isn't an option to use createPage and build several times a day.
I'm using onCreatePage here to create pages which works fine for my first route, but when I try to make an English route somehow it doesn't work.
gatby-node.js:
exports.onCreatePage = async ({ page, actions: { createPage } }) => {
if (page.path.match(/^\/listing/)) {
page.matchPath = '/listing/:id'
createPage(page)
}
if (page.path.match(/^\/en\/listing/)) {
page.matchPath = '/en/listing/:id'
createPage(page)
}
}
What I'm trying to achieve here is getting 2 dynamic routes like:
localhost:8000/listing/123 (this one works)
localhost:8000/en/listing/123 (this one doesn't work)
My pages folder looks like this:
pages
---listing.tsx
---en/
------listing.tsx
Can anyone see what I'm doing wrong here?
--
P.S. I want to use SSR (available since Gatsby v4) by using the getServerData() in the templates for these pages. Will that work together with pages created dynamically with onCreatePage or is there a better approach?
According to what we've discussed in the comment section: the fact that the /en/ path is never created, hence is not entering the following condition:
if (page.path.match(/^\/en\/listing/)) {
page.matchPath = '/en/listing/:id'
createPage(page)
}
Points me to think that the issue is on your createPages API rather than onCreatePage, which means that your english page is not even created.
Keep in mind that onCreatePage API is a callback called when a page is created, so it's triggered after createPages.
If you add a console.log(page.path) you shouldn't see the English page in the IDE/text editor console so try debugging how are you creating the /en/ route because it seems that onCreatePage doesn't have any problem.
I have a web api 2 project, and in my code I do some routing stuff myself.
I have all my actions going to a single route, so hitting localhost/<anything> will always go to one route.
In that route I am doing some custom pattern matching.
If the user goes to /Kittens/AdoptAKitten/12345
It will match against a template I have using regex, defined as /Kittens/AdoptAKitten/{something}
The problem is when I host my project locally, it ends up at localhost/KITTENCORP.ADOPTION/ which is the name of my project. As a result the route matching doesn't work.
I am not sure how to take into account this 'root' address. Previously I was just looking at the domain part of the Uri object but I need to include this part in the comparison to make it work (or disregard/remove it).
This code will however also be deployed to a server somewhere at which point it will probably be hosted on adoptionservice.kittens.org and thus adoptionservice.kittens.org/Kittens/AdoptAKitten/12345 will be the url. So it has to account for both situations.
Any ideas how I can resolve this problem?
For anyone stumbling across this and wondering the same thing, I fixed it with this code:
// When hosted in IIS it may get a virtual path such as localhost/KittenLibrary that needs including in comparisons
if (!string.IsNullOrEmpty(HttpRuntime.AppDomainAppVirtualPath))
{
urlStart = UrlCombine(urlStart, HttpRuntime.AppDomainAppVirtualPath);
}
UrlCombine is a function I pinched from another SO question:
private static string UrlCombine(string url1, string url2)
{
if (url1.Length == 0)
{
return url2;
}
if (url2.Length == 0)
{
return url1;
}
url1 = url1.TrimEnd('/', '\\');
url2 = url2.TrimStart('/', '\\');
return string.Format("{0}/{1}", url1, url2);
}
I'm looking to use Ghost to host both a blog and a static website, so the structure might look something like this:
/: the landing page (not the blog landing page, doesn't need access to posts)
/blog/: the blog landing page (needs access to posts that index.hbs typically has access to)
/page1/, etc: static pages which will use page.hbs or page-page1.hbs as needed
/blog-post-whatever/, etc: blog posts which will use post.hbs
The only thing I foresee being an issue is that only index.hbs (as far as I know) is passed the posts template variable (see code on GitHub here).
Before I go submit a pull request, it'd be nice to know whether:
Is there an existing way to get access to the posts variable in page.hbs?
If not, is it worthwhile to submit a pull request for this?
If yes, would we really want to send posts to all the pages? or should the pull request split apart page.hbs and only send it to those? or is there a better way to do this?
If you don't mind hacking the Ghost core files then here is how you can do it for the current version of Ghost (0.7.4). This hack will require recreation if upgrading to a new Ghost version.
First create the template files (that will not change if you upgrade):
Create the home page template in:
contents/themes/theme-name/home.hbs
home.hbs now supersedes index.hbs and will be rendered instead of it.
Also create the blog template file in:
contents/themes/theme-name/blog.hbs
The handlebars element that adds the paged posts is
{{> "loop"}}
so this should be in the blog.hbs file.
Again, the above files do not change if you upgrade to a new version of Ghost.
Now edit the following files in the core/server directory:
I have added a few lines before and after the sections of code that you need to add so that you can more easily find the location of where the new code needs to be added.
/core/server/routes/frontend.js:
Before:
indexRouter.route('/').get(frontend.index);
indexRouter.route('/' + routeKeywords.page + '/:page/').get(frontend.index);
After:
indexRouter.route('/').get(frontend.index);
indexRouter.route('/blog/').get(frontend.blog);
indexRouter.route('/' + routeKeywords.page + '/:page/').get(frontend.index);
This calls the Frontend controller that will render the blog page with the same data level as ‘index’ and ‘home’ (the default is load a the first page of the recent posts) thus enabling us to use the “loop” in the /blog/ page.
/core/server/controllers/frontend/index.js
Before:
frontendControllers = {
index: renderChannel('index'),
tag: renderChannel('tag'),
After:
frontendControllers = {
index: renderChannel('index'),
blog: renderChannel('blog'),
tag: renderChannel('tag'),
/core/server/controllers/frontend/channel-config.js
Before:
getConfig = function getConfig(name) {
var defaults = {
index: {
name: 'index',
route: '/',
frontPageTemplate: 'home'
},
tag: {
After:
getConfig = function getConfig(name) {
var defaults = {
index: {
name: 'index',
route: '/',
frontPageTemplate: 'home'
},
blog: {
name: 'blog',
route: '/blog/',
frontPageTemplate: 'blog'
},
tag: {
/core/server/controllers/frontend/channel-config.js
Before:
indexPattern = new RegExp('^\\/' + config.routeKeywords.page + '\\/'),
rssPattern = new RegExp('^\\/rss\\/'),
homePattern = new RegExp('^\\/$');
After:
indexPattern = new RegExp('^\\/' + config.routeKeywords.page + '\\/'),
rssPattern = new RegExp('^\\/rss\\/'),
blogPattern = new RegExp('^\\/blog\\/'),
homePattern = new RegExp('^\\/$');
and
Before:
if (indexPattern.test(res.locals.relativeUrl)) {
res.locals.context.push('index');
} else if (homePattern.test(res.locals.relativeUrl)) {
res.locals.context.push('home');
res.locals.context.push('index');
} else if (rssPattern.test(res.locals.relativeUrl)) {
res.locals.context.push('rss');
} else if (privatePattern.test(res.locals.relativeUrl)) {
res.locals.context.push('private');
After:
if (indexPattern.test(res.locals.relativeUrl)) {
res.locals.context.push('index');
} else if (homePattern.test(res.locals.relativeUrl)) {
res.locals.context.push('home');
res.locals.context.push('index');
} else if (blogPattern.test(res.locals.relativeUrl)) {
res.locals.context.push('blog');
} else if (rssPattern.test(res.locals.relativeUrl)) {
res.locals.context.push('rss');
} else if (privatePattern.test(res.locals.relativeUrl)) {
res.locals.context.push('private');
Restart the server and you should see the new /blog/ page come up with the list of recent blog posts
Here's a solution that I am currently using. I have an off-canvas nav that I want to use to display links to my latest posts. On the home page, this works great: I iterate over posts and render some links. On the other pages, I don't have the posts variable at my disposal.
My solution is this: wrap the pertinent post links on the homepage in a div with an id of "posts", then I make an ajax request for that specific content (using jQuery's load) and inject it into my nav on all other pages except the home page. Here's a link to jQuery's load docs.
Code:
index.hbs
<div id='posts'>
{{#foreach posts}}
<li>
{{{title}}}
</li>
{{/foreach}}
</div>
app.js
var $latest = $('#posts');
if ( location.pathname !== '/' )
$latest.load('/ #posts li');
There is no way currently (Ghost v0.5.8) to access posts within a page template.
I would think its probably not worth submitting the pull request. The Ghost devs seem to have their own plans for this and keep saying they'll get around to this functionality. Hopefully its soon because it is basic functionality.
The best way to go about this would be to hack the core yourself. Eventually the better way to do this would be with a hook. It looks like the Ghost API will eventually open up to the point where you can hook into core functions for plugins pretty much the same way Wordpress does it. https://github.com/TryGhost/Ghost/wiki/Apps-Getting-Started-for-Ghost-Devs
If this is a theme others will be using I would recommend working within the current limitations of Ghost. It's super annoying, I know, but in the long run its best for your users and your reputation.
If this is only for you, then I would hack the core to expose a list of posts or pages as locals in each route. If you're familiar with Express then this shouldn't be very difficult.
I think the way you've done it is pretty creative and there's a part of me that likes it but it really is a seriously ugly hack. If you find yourself hacking these kinds of solutions together a lot then Ghost might not be the tool you want to be using.
A better solution than briangonzalez one, is to get the posts-info from the RSS-feed, instead of the home page.
See this gist for how it can be done.
Now you can use the ghost-url-api, it's currently in beta but you can activate it in the administration (Settings > labs).
For example the {{#get}} helper can be use like this in a static page:
{{#get "posts" limit="3" include="author,tags"}}
{{#foreach posts}}
... call the loop
{{/foreach}}
{{/get}}
More informations :
http://themes.ghost.org/docs/ghost-url-api
As of Ghost v0.9.0, the Channels API is still under development. However, achieving this is much simpler now. It still requires modification of core files, but I'm planning on submitting some pull requests soon. Currently, one downside of the following method is that your sitemap-pages.xml will not contain the /blog/ URL.
Thanks to #Yuval's answer for kicking this off.
Create a template file for your index page with the path content/themes/theme-name/index.hbs. This can contain whatever you would like for your "static" homepage.
Create a template file for your blog index page with the path content/themes/theme-name/blog.hbs. This simply needs to contain:
{{> "loop"}}
In /core/server/controllers/frontend/channel-config.js:
Edit the var defaults object to include:
blog: {
name: 'blog',
route: '/blog/'
}
I'm using the wai-app-static static package to serve a small website. Originally I called it as:
staticApp defaultFileServerSettings root
and all was right with the world. I wanted to switch to using defaultWebAppSettings, though, (as this is a website). I was able to get that to work, such that if I went to http://localhost:3000/index.html, it was fine, but I also need to set up a redirect from the root folder to the index site (viz. http://localhost:3000 --> http://localhost:3000/index.html).
Based on what I saw in the code, I tried a couple of variations of:
(defaultWebAppSettings root) { ssIndices = map unsafeToPiece ["index.html"],
ssRedirectToIndex = True }
I'm able to compile and run the server, but I can't get the redirection to work.
Any pointers or ideas would be greatly appreciated!
Thanks
Hmm, I didn't know about the ssIndices or ssRedirectToIndex settings. What I did for my app that has dynamic and static parts, was on requests to /, alter that request to say /index.html instead and send it to the "static server".
https://github.com/LeifW/online-typechecker/blob/master/index.hs#L20
This code works for me
httpApp :: Wai.Application
httpApp = Static.staticApp $ s {Static.ssIndices = [Static.unsafeToPiece "index.html"]} where s = Static.defaultWebAppSettings "./static"
I have a JSP page which is named as erSelection.jsp. But, at the deployment in the configuration file it is stored as ERSelection.jsp as a result page not found error is found. Is there a way in JSF we can redirect the URL http://localhost:8080/Test/ERSelection.faces to erSelection.faces.
If just renaming the physical file is really not an option, your best bet is to either create a custom filter which does that
if (request.getRequestURI().endsWith("/ERSelection.faces")) {
response.sendRedirect(request.getContextPath() + "/erSelection.faces");
// You may want to do a 301 instead with a Location header.
} else {
chain.doFilter(request, response);
}
or to grab a more customizeable URL rewrite filter which does that by a simple configuration file, such as the Tuckey's URLRewriteFilter.