mirror of
https://github.com/trambarhq/relaks-wordpress-example.git
synced 2025-09-03 21:22:34 +02:00
Inserted new code into README.
This commit is contained in:
289
README.md
289
README.md
@@ -147,10 +147,10 @@ The handler detects whether the remote agent is a search-engine spider and handl
|
||||
```javascript
|
||||
async function handlePageRequest(req, res, next) {
|
||||
try {
|
||||
let path = req.url;
|
||||
let noJS = (req.query.js === '0');
|
||||
let target = (req.isSpider() || noJS) ? 'seo' : 'hydrate';
|
||||
let page = await PageRenderer.generate(path, target);
|
||||
const path = req.url;
|
||||
const noJS = (req.query.js === '0');
|
||||
const target = (req.isSpider() || noJS) ? 'seo' : 'hydrate';
|
||||
const page = await PageRenderer.generate(path, target);
|
||||
if (target === 'seo') {
|
||||
// not caching content generated for SEO
|
||||
res.set({ 'X-Accel-Expires': 0 });
|
||||
@@ -173,11 +173,11 @@ async function handlePageRequest(req, res, next) {
|
||||
async function generate(path, target) {
|
||||
console.log(`Regenerating page: ${path}`);
|
||||
// retrieve cached JSON through Nginx
|
||||
let host = NGINX_HOST;
|
||||
const host = NGINX_HOST;
|
||||
// create a fetch() that remembers the URLs used
|
||||
let sourceURLs = [];
|
||||
let agent = new HTTP.Agent({ keepAlive: true });
|
||||
let fetch = (url, options) => {
|
||||
const sourceURLs = [];
|
||||
const agent = new HTTP.Agent({ keepAlive: true });
|
||||
const fetch = (url, options) => {
|
||||
if (url.startsWith(host)) {
|
||||
sourceURLs.push(url.substr(host.length));
|
||||
options = addHostHeader(options);
|
||||
@@ -185,21 +185,19 @@ async function generate(path, target) {
|
||||
}
|
||||
return CrossFetch(url, options);
|
||||
};
|
||||
let options = { host, path, target, fetch };
|
||||
let appHTML = await FrontEnd.render(options);
|
||||
let htmlTemplate = await FS.readFileAsync(HTML_TEMPLATE, 'utf-8');
|
||||
let html = htmlTemplate.replace(`<!--REACT-->`, appHTML);
|
||||
const options = { host, path, target, fetch };
|
||||
const frontEndHTML = await FrontEnd.render(options);
|
||||
const htmlTemplate = await FS.readFileAsync(HTML_TEMPLATE, 'utf-8');
|
||||
let html = htmlTemplate.replace(`<!--REACT-->`, frontEndHTML);
|
||||
if (target === 'hydrate') {
|
||||
// add <noscript> tag to redirect to SEO version
|
||||
let meta = `<meta http-equiv=refresh content="0; url=?js=0">`;
|
||||
const meta = `<meta http-equiv=refresh content="0; url=?js=0">`;
|
||||
html += `<noscript>${meta}</noscript>`;
|
||||
}
|
||||
return { path, target, sourceURLs, html };
|
||||
}
|
||||
```
|
||||
|
||||
`FrontEnd.render()` returns a ReactElement containing plain HTML child elements. We use [React DOM Server](https://reactjs.org/docs/react-dom-server.html#rendertostring) to convert that to actual HTML text. Then we stick it into our [HTML template](https://github.com/trambarhq/relaks-wordpress-example/blob/master/src/index.html), where a HTML comment sits inside the element that would host the root React component.
|
||||
|
||||
`FrontEnd.render()` is a function exported by our front-end code(https://github.com/trambarhq/relaks-wordpress-example/blob/master/src/ssr.js#L67):
|
||||
|
||||
```javascript
|
||||
@@ -223,8 +221,8 @@ async function render(options) {
|
||||
|
||||
const ssrElement = createElement(FrontEnd, { dataSource, routeManager, ssr: options.target });
|
||||
const rootNode = await harvest(ssrElement);
|
||||
const appHTML = renderToString(rootNode);
|
||||
return appHTML;
|
||||
const html = renderToString(rootNode);
|
||||
return html;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -232,6 +230,8 @@ The code initiates the data source and the route manager. Using these as props,
|
||||
|
||||

|
||||
|
||||
The tree is then converted to a text string using React DOM Server's [renderToString()](https://reactjs.org/docs/react-dom-server.html#rendertostring).
|
||||
|
||||
Our front-end is built with the help of [Relaks](https://github.com/trambarhq/relaks), a library that let us make asynchronous calls within a React component's render method. Data retrievals are done as part of the rendering cycle. This model makes SSR very straight forward. To render a page, we just call the render methods of all its components and wait for them to finish.
|
||||
|
||||
### JSON data retrieval
|
||||
@@ -242,9 +242,9 @@ The following handler is invoked when Nginx requests a JSON file (i.e. when a ca
|
||||
async function handleJSONRequest(req, res, next) {
|
||||
try {
|
||||
// exclude asterisk
|
||||
let root = req.route.path.substr(0, req.route.path.length - 1);
|
||||
let path = `/wp-json/${req.url.substr(root.length)}`;
|
||||
let json = await JSONRetriever.fetch(path);
|
||||
const root = req.route.path.substr(0, req.route.path.length - 1);
|
||||
const path = `/wp-json/${req.url.substr(root.length)}`;
|
||||
const json = await JSONRetriever.fetch(path);
|
||||
if (json.total) {
|
||||
res.set({ 'X-WP-Total': json.total });
|
||||
}
|
||||
@@ -261,9 +261,9 @@ async function handleJSONRequest(req, res, next) {
|
||||
```javascript
|
||||
async function fetch(path) {
|
||||
console.log(`Retrieving data: ${path}`);
|
||||
let url = `${WORDPRESS_HOST}${path}`;
|
||||
let res = await CrossFetch(url);
|
||||
let resText = await res.text();
|
||||
const url = `${WORDPRESS_HOST}${path}`;
|
||||
const res = await CrossFetch(url, { agent });
|
||||
const resText = await res.text();
|
||||
let object;
|
||||
try {
|
||||
object = JSON.parse(resText);
|
||||
@@ -275,14 +275,14 @@ async function fetch(path) {
|
||||
}
|
||||
}
|
||||
if (res.status >= 400) {
|
||||
let msg = (object && object.message) ? object.message : resText;
|
||||
let err = new Error(msg);
|
||||
const msg = (object && object.message) ? object.message : resText;
|
||||
const err = new Error(msg);
|
||||
err.status = res.status;
|
||||
throw err;
|
||||
}
|
||||
let total = parseInt(res.headers.get('X-WP-Total'));
|
||||
const total = parseInt(res.headers.get('X-WP-Total'));
|
||||
removeSuperfluousProps(path, object);
|
||||
let text = JSON.stringify(object);
|
||||
const text = JSON.stringify(object);
|
||||
return { path, text, total };
|
||||
}
|
||||
```
|
||||
@@ -296,29 +296,29 @@ The [Proxy Cache Purge](https://wordpress.org/plugins/varnish-http-purge/) sends
|
||||
```javascript
|
||||
async function handlePurgeRequest(req, res) {
|
||||
// verify that require is coming from WordPress
|
||||
let remoteIP = req.connection.remoteAddress;
|
||||
const remoteIP = req.connection.remoteAddress;
|
||||
res.end();
|
||||
let wordpressIP = await dnsCache.lookupAsync(WORDPRESS_HOST.replace(/^https?:\/\//, ''));
|
||||
const wordpressIP = await dnsCache.lookupAsync(WORDPRESS_HOST.replace(/^https?:\/\//, ''));
|
||||
if (remoteIP !== `::ffff:${wordpressIP}`) {
|
||||
return;
|
||||
}
|
||||
|
||||
let url = req.url;
|
||||
let method = req.headers['x-purge-method'];
|
||||
const url = req.url;
|
||||
const method = req.headers['x-purge-method'];
|
||||
if (method === 'regex' && url === '/.*') {
|
||||
pageDependencies = {};
|
||||
await NginxCache.purge(/.*/);
|
||||
await PageRenderer.prefetch('/');
|
||||
} else if (method === 'default') {
|
||||
// look for URLs that looks like /wp-json/wp/v2/pages/4/
|
||||
let m = /^\/wp\-json\/(\w+\/\w+\/\w+)\/(\d+)\/$/.exec(url);
|
||||
const m = /^\/wp\-json\/(\w+\/\w+\/\w+)\/(\d+)\/$/.exec(url);
|
||||
if (!m) {
|
||||
return;
|
||||
}
|
||||
|
||||
// purge matching JSON files
|
||||
let folderPath = m[1];
|
||||
let pattern = new RegExp(`^/json/${folderPath}.*`);
|
||||
const folderPath = m[1];
|
||||
const pattern = new RegExp(`^/json/${folderPath}.*`);
|
||||
await NginxCache.purge(pattern);
|
||||
|
||||
// purge the timestamp so CSR code knows something has changed
|
||||
@@ -326,7 +326,7 @@ async function handlePurgeRequest(req, res) {
|
||||
|
||||
// look for pages that made use of the purged JSONs
|
||||
for (let [ path, sourceURLs ] of Object.entries(pageDependencies)) {
|
||||
let affected = sourceURLs.some((sourceURL) => {
|
||||
const affected = sourceURLs.some((sourceURL) => {
|
||||
return pattern.test(sourceURL);
|
||||
});
|
||||
if (affected) {
|
||||
@@ -358,8 +358,8 @@ The handle for timestamp requests is extremely simple:
|
||||
```javascript
|
||||
async function handleTimestampRequest(req, res, next) {
|
||||
try {
|
||||
let now = new Date;
|
||||
let ts = now.toISOString();
|
||||
const now = new Date;
|
||||
const ts = now.toISOString();
|
||||
res.set({ 'Cache-Control': CACHE_CONTROL });
|
||||
res.type('text').send(ts);
|
||||
} catch (err) {
|
||||
@@ -441,7 +441,7 @@ We want our front-end to handle WordPress permalinks correctly. This makes page
|
||||
|
||||
```javascript
|
||||
routeManager.addEventListener('beforechange', (evt) => {
|
||||
let route = new Route(routeManager, dataSource);
|
||||
const route = new Route(routeManager, dataSource);
|
||||
evt.postponeDefault(route.setParameters(evt, true));
|
||||
});
|
||||
```
|
||||
@@ -449,7 +449,7 @@ routeManager.addEventListener('beforechange', (evt) => {
|
||||
`route.setParameters()` ([routing.js](https://github.com/trambarhq/relaks-wordpress-example/blob/master/src/routing.js#L62)) basically displaces the default parameter extraction mechanism. Our routing table is reduced to the following:
|
||||
|
||||
```javascript
|
||||
let routes = {
|
||||
const routes = {
|
||||
'page': { path: '*' },
|
||||
};
|
||||
```
|
||||
@@ -460,7 +460,7 @@ Which simply matches any URL.
|
||||
|
||||
```javascript
|
||||
async setParameters(evt, fallbackToRoot) {
|
||||
let params = await this.getParameters(evt.path, evt.query);
|
||||
const params = await this.getParameters(evt.path, evt.query);
|
||||
if (params) {
|
||||
params.module = require(`pages/${params.pageType}-page`);
|
||||
_.assign(evt.params, params);
|
||||
@@ -480,8 +480,8 @@ The key parameter is `pageType`, which is used to load one of the [page componen
|
||||
At a glance `route.getParameters()` ([routing.js](https://github.com/trambarhq/relaks-wordpress-example/blob/master/src/routing.js#L77)) might seem incredibly inefficient. To see if a URL points to a page, it fetches all pages and see if one of them has that URL:
|
||||
|
||||
```javascript
|
||||
let allPages = await wp.fetchPages();
|
||||
let page = _.find(allPages, matchLink);
|
||||
const allPages = await wp.fetchPages();
|
||||
const page = _.find(allPages, matchLink);
|
||||
if (page) {
|
||||
return { pageType: 'page', pageSlug: page.slug, siteURL };
|
||||
}
|
||||
@@ -490,8 +490,8 @@ if (page) {
|
||||
It does the same check on categories:
|
||||
|
||||
```javascript
|
||||
let allCategories = await wp.fetchCategories();
|
||||
let category = _.find(allCategories, matchLink);
|
||||
const allCategories = await wp.fetchCategories();
|
||||
const category = _.find(allCategories, matchLink);
|
||||
if (category) {
|
||||
return { pageType: 'category', categorySlug: category.slug, siteURL };
|
||||
}
|
||||
@@ -503,12 +503,12 @@ Most of the time, the data in question would be cached already. The top nav load
|
||||
|
||||
```javascript
|
||||
getObjectURL(object) {
|
||||
let { siteURL } = this.params;
|
||||
let link = object.link;
|
||||
const { siteURL } = this.params;
|
||||
const link = object.link;
|
||||
if (!_.startsWith(link, siteURL)) {
|
||||
throw new Error(`Object URL does not match site URL`);
|
||||
}
|
||||
let path = link.substr(siteURL.length);
|
||||
const path = link.substr(siteURL.length);
|
||||
return this.composeURL({ path });
|
||||
}
|
||||
```
|
||||
@@ -519,7 +519,7 @@ For links to categories and tags, we perform explicit prefetching:
|
||||
|
||||
```javascript
|
||||
prefetchObjectURL(object) {
|
||||
let url = this.getObjectURL(object);
|
||||
const url = this.getObjectURL(object);
|
||||
setTimeout(() => { this.loadPageData(url) }, 50);
|
||||
return url;
|
||||
}
|
||||
@@ -563,12 +563,6 @@ export {
|
||||
};
|
||||
```
|
||||
|
||||
`WelcomePageSync`, meanwhile, delegate the task of rendering the list of posts to `PostList`:
|
||||
|
||||
```javascript
|
||||
/* ... */
|
||||
```
|
||||
|
||||
### PostList
|
||||
|
||||
The render method of `PostList` [post-list.jsx](https://github.com/trambarhq/relaks-wordpress-example/blob/master/src/widgets/post-list.jsx) doesn't do anything special:
|
||||
@@ -635,10 +629,193 @@ export {
|
||||
};
|
||||
```
|
||||
|
||||
The only thing noteworthy about the component is that it perform data load on scroll:
|
||||
The only thing noteworthy about the component is that it perform data load on scroll.
|
||||
|
||||
## PostListView
|
||||
|
||||
```javascript
|
||||
/* ... */
|
||||
import _ from 'lodash';
|
||||
import Moment from 'moment';
|
||||
import React from 'react';
|
||||
|
||||
import { HTML } from 'widgets/html';
|
||||
import { MediaView } from 'widgets/media-view';
|
||||
|
||||
function PostListView(props) {
|
||||
const { route, post, media } = props;
|
||||
const title = _.get(post, 'title.rendered', '');
|
||||
const excerptRendered = _.get(post, 'excerpt.rendered', '');
|
||||
const excerpt = cleanExcerpt(excerptRendered);
|
||||
const url = route.prefetchObjectURL(post);
|
||||
const published = _.get(post, 'date_gmt');
|
||||
const date = (published) ? Moment(published).format('L') : '';
|
||||
|
||||
if (media) {
|
||||
return (
|
||||
<div className="post-list-view with-media">
|
||||
<div className="media">
|
||||
<MediaView media={media} />
|
||||
</div>
|
||||
<div className="text">
|
||||
<div className="headline">
|
||||
<h3 className="title">
|
||||
<a href={url}><HTML text={title} /></a>
|
||||
</h3>
|
||||
<div className="date">{date}</div>
|
||||
</div>
|
||||
<div className="excerpt">
|
||||
<HTML text={excerpt} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div className="post-list-view">
|
||||
<div className="headline">
|
||||
<h3 className="title">
|
||||
<a href={url}><HTML text={title} /></a>
|
||||
</h3>
|
||||
<div className="date">{date}</div>
|
||||
</div>
|
||||
<div className="excerpt">
|
||||
<HTML text={excerpt} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function cleanExcerpt(excerpt) {
|
||||
const index = excerpt.indexOf('<p class="link-more">');
|
||||
if (index !== -1) {
|
||||
excerpt = excerpt.substr(0, index);
|
||||
}
|
||||
return excerpt;
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
PostListView,
|
||||
};
|
||||
```
|
||||
|
||||
## PostPage
|
||||
|
||||
```javascript
|
||||
import _ from 'lodash';
|
||||
import Moment from 'moment';
|
||||
import React from 'react';
|
||||
import Relaks, { useProgress } from 'relaks';
|
||||
|
||||
import { Breadcrumb } from 'widgets/breadcrumb';
|
||||
import { PostView } from 'widgets/post-view';
|
||||
import { TagList } from 'widgets/tag-list';
|
||||
import { CommentSection } from 'widgets/comment-section';
|
||||
|
||||
async function PostPage(props) {
|
||||
const { wp, route } = props;
|
||||
const { postSlug } = route.params;
|
||||
const [ show ] = useProgress();
|
||||
|
||||
render();
|
||||
const post = await wp.fetchPost(postSlug);
|
||||
render();
|
||||
const categories = await findCategoryChain(post);
|
||||
render();
|
||||
const author = await wp.fetchAuthor(post);
|
||||
render();
|
||||
const tags = await wp.fetchTagsOfPost(post);
|
||||
render()
|
||||
let comments;
|
||||
if (!wp.ssr) {
|
||||
comments = await wp.fetchComments(post);
|
||||
render();
|
||||
}
|
||||
|
||||
function render() {
|
||||
const trail = [ { label: 'Categories' } ];
|
||||
if (categories) {
|
||||
for (let category of categories) {
|
||||
const label = _.get(category, 'name', '');
|
||||
const url = route.prefetchObjectURL(category);
|
||||
trail.push({ label, url });
|
||||
}
|
||||
}
|
||||
show(
|
||||
<div className="page">
|
||||
<Breadcrumb trail={trail} />
|
||||
<PostView post={post} author={author} transform={route.transformNode} />
|
||||
<TagList route={route} tags={tags} />
|
||||
<CommentSection comments={comments} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
async function findCategoryChain(post) {
|
||||
if (!post) return [];
|
||||
const allCategories = await wp.fetchCategories();
|
||||
|
||||
// add categories, including their parents as well
|
||||
const applicable = [];
|
||||
const include = (id) => {
|
||||
const category = _.find(allCategories, { id })
|
||||
if (category) {
|
||||
if (!_.includes(applicable, category)) {
|
||||
applicable.push(category);
|
||||
}
|
||||
// add parent category as well
|
||||
include(category.parent);
|
||||
}
|
||||
};
|
||||
for (let id of post.categories) {
|
||||
include(id);
|
||||
}
|
||||
|
||||
// see how recently a category was visited
|
||||
const historyIndex = (category) => {
|
||||
const predicate = { params: { categorySlug: category.slug }};
|
||||
return _.findLastIndex(route.history, predicate);
|
||||
};
|
||||
// see how deep a category is
|
||||
const depth = (category) => {
|
||||
if (category.parent) {
|
||||
const predicate = { id: category.parent };
|
||||
const parent = _.find(allCategories, predicate);
|
||||
if (parent) {
|
||||
return depth(parent) + 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
// order applicable categories based on how recently it was visited,
|
||||
// how deep it is, and alphabetically; the first criteria makes our
|
||||
// breadcrumb works more sensibly
|
||||
const ordered = _.orderBy(applicable, [ historyIndex, depth, 'name' ], [ 'desc', 'desc', 'asc' ]);
|
||||
const anchorCategory = _.first(ordered);
|
||||
|
||||
const trail = [];
|
||||
if (anchorCategory) {
|
||||
// add category and its ancestors
|
||||
for (let c = anchorCategory; c; c = _.find(applicable, { id: c.parent })) {
|
||||
trail.unshift(c);
|
||||
}
|
||||
// add applicable child categories
|
||||
for (let c = anchorCategory; c; c = _.find(applicable, { parent: c.id })) {
|
||||
if (c !== anchorCategory) {
|
||||
trail.push(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
return trail;
|
||||
}
|
||||
}
|
||||
|
||||
const component = Relaks.memo(PostPage);
|
||||
|
||||
export {
|
||||
component as default,
|
||||
};
|
||||
```
|
||||
|
||||
## Cordova deployment
|
||||
|
File diff suppressed because one or more lines are too long
@@ -25,42 +25,42 @@ class Route {
|
||||
}
|
||||
|
||||
getArchiveURL(date) {
|
||||
let { year, month } = date;
|
||||
const { year, month } = date;
|
||||
return this.composeURL({ path: `/date/${year}/${_.padStart(month, 2, '0')}/` });
|
||||
}
|
||||
|
||||
getObjectURL(object) {
|
||||
let { siteURL } = this.params;
|
||||
let link = object.link;
|
||||
const { siteURL } = this.params;
|
||||
const link = object.link;
|
||||
if (!_.startsWith(link, siteURL)) {
|
||||
throw new Error(`Object URL does not match site URL`);
|
||||
}
|
||||
let path = link.substr(siteURL.length);
|
||||
const path = link.substr(siteURL.length);
|
||||
return this.composeURL({ path });
|
||||
}
|
||||
|
||||
prefetchArchiveURL(date) {
|
||||
let url = this.getArchiveURL(date);
|
||||
const url = this.getArchiveURL(date);
|
||||
setTimeout(() => { this.loadPageData(url) }, 50);
|
||||
return url;
|
||||
}
|
||||
|
||||
prefetchObjectURL(object) {
|
||||
let url = this.getObjectURL(object);
|
||||
const url = this.getObjectURL(object);
|
||||
setTimeout(() => { this.loadPageData(url) }, 50);
|
||||
return url;
|
||||
}
|
||||
|
||||
composeURL(urlParts) {
|
||||
let context = this.routeManager.context;
|
||||
const context = this.routeManager.context;
|
||||
this.routeManager.rewrite('to', urlParts, context);
|
||||
let url = this.routeManager.compose(urlParts);
|
||||
const url = this.routeManager.compose(urlParts);
|
||||
url = this.routeManager.applyFallback(url);
|
||||
return url;
|
||||
}
|
||||
|
||||
async setParameters(evt, fallbackToRoot) {
|
||||
let params = await this.getParameters(evt.path, evt.query);
|
||||
const params = await this.getParameters(evt.path, evt.query);
|
||||
if (params) {
|
||||
params.module = require(`pages/${params.pageType}-page`);
|
||||
_.assign(evt.params, params);
|
||||
@@ -77,17 +77,17 @@ class Route {
|
||||
async getParameters(path, query, fallbackToRoot) {
|
||||
// get the site URL and see what the page's URL would be if it
|
||||
// were on WordPress itself
|
||||
let wp = new Wordpress(this.dataSource);
|
||||
let site = await wp.fetchSite();
|
||||
let siteURL = _.trimEnd(site.url, '/');
|
||||
let link = _.trimEnd(siteURL + path, '/');
|
||||
let matchLink = (obj) => {
|
||||
const wp = new Wordpress(this.dataSource);
|
||||
const site = await wp.fetchSite();
|
||||
const siteURL = _.trimEnd(site.url, '/');
|
||||
const link = _.trimEnd(siteURL + path, '/');
|
||||
const matchLink = (obj) => {
|
||||
return _.trimEnd(obj.link, '/') === link;
|
||||
};
|
||||
let slugs = _.filter(_.split(path, '/'));
|
||||
const slugs = _.filter(_.split(path, '/'));
|
||||
|
||||
// see if it's a search
|
||||
let search = query.s;
|
||||
const search = query.s;
|
||||
if (search) {
|
||||
return { pageType: 'search', search, siteURL };
|
||||
}
|
||||
@@ -99,13 +99,13 @@ class Route {
|
||||
|
||||
// see if it's pointing to an archive
|
||||
if (slugs[0] === 'date' && /^\d+$/.test(slugs[1]) && /^\d+$/.test(slugs[2]) && slugs.length == 3) {
|
||||
let date = {
|
||||
const date = {
|
||||
year: parseInt(slugs[1]),
|
||||
month: parseInt(slugs[2]),
|
||||
};
|
||||
return { pageType: 'archive', date, siteURL };
|
||||
} else if (/^\d+$/.test(slugs[0]) && /^\d+$/.test(slugs[1]) && slugs.length == 2) {
|
||||
let date = {
|
||||
const date = {
|
||||
year: parseInt(slugs[0]),
|
||||
month: parseInt(slugs[1]),
|
||||
};
|
||||
@@ -114,56 +114,56 @@ class Route {
|
||||
|
||||
// see if it's pointing to a post by ID
|
||||
if (slugs[0] === 'archives' && /^\d+$/.test(slugs[1])) {
|
||||
let postID = parseInt(slugs[1]);
|
||||
let post = await wp.fetchPost(postID);
|
||||
const postID = parseInt(slugs[1]);
|
||||
const post = await wp.fetchPost(postID);
|
||||
if (post) {
|
||||
return { pageType: 'post', postSlug: post.slug, siteURL };
|
||||
}
|
||||
}
|
||||
|
||||
// see if it's pointing to a page
|
||||
let allPages = await wp.fetchPages();
|
||||
let page = _.find(allPages, matchLink);
|
||||
const allPages = await wp.fetchPages();
|
||||
const page = _.find(allPages, matchLink);
|
||||
if (page) {
|
||||
return { pageType: 'page', pageSlug: page.slug, siteURL };
|
||||
}
|
||||
|
||||
// see if it's pointing to a category
|
||||
let allCategories = await wp.fetchCategories();
|
||||
let category = _.find(allCategories, matchLink);
|
||||
const allCategories = await wp.fetchCategories();
|
||||
const category = _.find(allCategories, matchLink);
|
||||
if (category) {
|
||||
return { pageType: 'category', categorySlug: category.slug, siteURL };
|
||||
}
|
||||
|
||||
// see if it's pointing to a popular tag
|
||||
let topTags = await wp.fetchTopTags();
|
||||
let topTag = _.find(topTags, matchLink);
|
||||
const topTags = await wp.fetchTopTags();
|
||||
const topTag = _.find(topTags, matchLink);
|
||||
if (topTag) {
|
||||
return { pageType: 'tag', tagSlug: topTag.slug, siteURL };
|
||||
}
|
||||
|
||||
// see if it's pointing to a not-so popular tag
|
||||
if (slugs[0] === 'tag' && slugs.length === 2) {
|
||||
let tag = await wp.fetchTag(slugs[1]);
|
||||
const tag = await wp.fetchTag(slugs[1]);
|
||||
if (tag) {
|
||||
return { pageType: 'tag', tagSlug: tag.slug, siteURL };
|
||||
}
|
||||
}
|
||||
|
||||
// see if it's pointing to a post
|
||||
let postSlug = _.last(slugs);
|
||||
const postSlug = _.last(slugs);
|
||||
if (/^\d+\-/.test(postSlug)) {
|
||||
// delete post ID in front of slug
|
||||
postSlug = postSlug.replace(/^\d+\-/, '');
|
||||
}
|
||||
let post = await wp.fetchPost(postSlug);
|
||||
const post = await wp.fetchPost(postSlug);
|
||||
if (post) {
|
||||
return { pageType: 'post', postSlug, siteURL };
|
||||
}
|
||||
|
||||
// see if it's pointing to a tag when no prefix is used
|
||||
let tagSlug = _.last(slugs);
|
||||
let tag = await wp.fetchTag(tagSlug);
|
||||
const tagSlug = _.last(slugs);
|
||||
const tag = await wp.fetchTag(tagSlug);
|
||||
if (tag) {
|
||||
return { pageType: 'tag', tagSlug: tag.slug, siteURL };
|
||||
}
|
||||
@@ -171,21 +171,21 @@ class Route {
|
||||
|
||||
async loadPageData(url) {
|
||||
try {
|
||||
let urlParts = this.routeManager.parse(url);
|
||||
let context = {};
|
||||
const urlParts = this.routeManager.parse(url);
|
||||
const context = {};
|
||||
this.routeManager.rewrite('from', urlParts, context);
|
||||
let params = await this.getParameters(urlParts.path, urlParts.query);
|
||||
const params = await this.getParameters(urlParts.path, urlParts.query);
|
||||
if (params) {
|
||||
let wp = new Wordpress(this.dataSource);
|
||||
const wp = new Wordpress(this.dataSource);
|
||||
if (params.postSlug) {
|
||||
await wp.fetchPost(params.postSlug);
|
||||
} else if (params.pageSlug) {
|
||||
await wp.fetchPage(params.pageSlug);
|
||||
} else if (params.tagSlug) {
|
||||
let tag = await wp.fetchTag(params.tagSlug);
|
||||
const tag = await wp.fetchTag(params.tagSlug);
|
||||
await wp.fetchPostsWithTag(tag);
|
||||
} else if (params.categorySlug) {
|
||||
let category = await wp.fetchCategory(params.categorySlug);
|
||||
const category = await wp.fetchCategory(params.categorySlug);
|
||||
await wp.fetchPostsInCategory(category);
|
||||
} else if (params.date) {
|
||||
await wp.fetchPostsInMonth(params.date);
|
||||
@@ -198,11 +198,11 @@ class Route {
|
||||
|
||||
transformNode = (node) => {
|
||||
if (node.type === 'tag') {
|
||||
let { siteURL } = this.params;
|
||||
let siteURLInsecure = 'http:' + siteURL.substr(6);
|
||||
const { siteURL } = this.params;
|
||||
const siteURLInsecure = 'http:' + siteURL.substr(6);
|
||||
if (node.name === 'a') {
|
||||
let url = _.trim(node.attribs.href);
|
||||
let target;
|
||||
const url = _.trim(node.attribs.href);
|
||||
const target;
|
||||
if (url) {
|
||||
if (!_.startsWith(url, '/')) {
|
||||
if (_.startsWith(url, siteURL)) {
|
||||
@@ -227,7 +227,7 @@ class Route {
|
||||
}
|
||||
} else if (node.name === 'img') {
|
||||
// prepend image URL with site URL
|
||||
let url = _.trim(node.attribs.src);
|
||||
const url = _.trim(node.attribs.src);
|
||||
if (url && !/^https?:/.test(url)) {
|
||||
url = siteURL + url;
|
||||
node.attribs.src = url;
|
||||
@@ -240,7 +240,7 @@ class Route {
|
||||
}
|
||||
}
|
||||
|
||||
let routes = {
|
||||
const routes = {
|
||||
'page': { path: '*' },
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user