mirror of
https://github.com/trambarhq/relaks-wordpress-example.git
synced 2025-09-02 20:52:33 +02:00
Reworked routing so that WP permalinks arrangement is used (issue #13).
This commit is contained in:
@@ -25,13 +25,11 @@ server {
|
||||
proxy_cache_min_uses 1;
|
||||
proxy_cache_valid 200 301 302 120m;
|
||||
proxy_cache_valid 404 1m;
|
||||
proxy_hide_header Cache-Control;
|
||||
proxy_ignore_headers Cache-Control Expires Set-Cookie;
|
||||
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
add_header Cache-Control "public,max-age=0";
|
||||
add_header X-Cache-Date $upstream_http_date;
|
||||
add_header X-Cache-Status $upstream_cache_status;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -10,6 +10,7 @@ const HTML_TEMPLATE = `${__dirname}/client/index.html`;
|
||||
|
||||
async function generate(path, target) {
|
||||
// retrieve cached JSON through Nginx
|
||||
console.log(`Regenerating page: ${path}`);
|
||||
let host = `http://${NGINX_HOST}`;
|
||||
// create a fetch() that remembers the URLs used
|
||||
let sourceURLs = [];
|
||||
|
@@ -31,7 +31,7 @@ if (typeof(window) === 'object') {
|
||||
});
|
||||
routeManager.addEventListener('beforechange', (evt) => {
|
||||
let route = new Route(routeManager, dataSource);
|
||||
evt.postponeDefault(route.setPageType(evt.params));
|
||||
evt.postponeDefault(route.setParameters(evt));
|
||||
});
|
||||
routeManager.activate();
|
||||
await routeManager.start();
|
||||
@@ -57,7 +57,6 @@ if (typeof(window) === 'object') {
|
||||
let mtime = await res.text();
|
||||
if (mtime !== mtimeLast) {
|
||||
if (mtimeLast) {
|
||||
console.log('changed');
|
||||
dataSource.invalidate();
|
||||
}
|
||||
mtimeLast = mtime;
|
||||
@@ -84,7 +83,7 @@ if (typeof(window) === 'object') {
|
||||
});
|
||||
routeManager.addEventListener('beforechange', (evt) => {
|
||||
let route = new Route(routeManager, dataSource);
|
||||
evt.postponeDefault(route.setPageType(evt.params));
|
||||
evt.postponeDefault(route.setParameters(evt));
|
||||
});
|
||||
routeManager.activate();
|
||||
await routeManager.start(options.path);
|
||||
|
@@ -12,22 +12,16 @@ class ArchivePage extends AsyncComponent {
|
||||
|
||||
async renderAsync(meanwhile) {
|
||||
let { wp, route } = this.props;
|
||||
let { monthSlug, categorySlug } = route.params;
|
||||
let month = Moment(monthSlug);
|
||||
let { date } = route.params;
|
||||
let month = Moment(`${date.year}-${date.month}`);
|
||||
let props = {
|
||||
route,
|
||||
month,
|
||||
};
|
||||
meanwhile.show(<ArchivePageSync {...props} />);
|
||||
let after = month.toISOString();
|
||||
let before = month.clone().endOf('month').toISOString();
|
||||
meanwhile.show(<ArchivePageSync {...props} />);
|
||||
props.categories = await wp.fetchList('/wp/v2/categories/');
|
||||
meanwhile.show(<ArchivePageSync {...props} />);
|
||||
let url = `/wp/v2/posts/?after=${after}&before=${before}`;
|
||||
if (categorySlug) {
|
||||
let category = _.find(props.categories, { slug: categorySlug });
|
||||
url = `/wp/v2/posts/?after=${after}&before=${before}&categories=${category.id}`;
|
||||
}
|
||||
props.posts = await wp.fetchList(url);
|
||||
return <ArchivePageSync {...props} />;
|
||||
}
|
||||
@@ -37,23 +31,13 @@ class ArchivePageSync extends PureComponent {
|
||||
static displayName = 'ArchivePageSync';
|
||||
|
||||
render() {
|
||||
let { route, categories, posts, month } = this.props;
|
||||
let { monthSlug, categorySlug } = route.params;
|
||||
let { route, posts, month } = this.props;
|
||||
let monthLabel = month.format('MMMM YYYY');
|
||||
let monthURL = route.find([ monthSlug ]);
|
||||
let trail = [ { label: 'Archive' } ];
|
||||
if (categorySlug) {
|
||||
let category = _.find(categories, { slug: categorySlug });
|
||||
let categoryLabel = _.get(category, 'name', '');
|
||||
trail.push({ label: monthLabel, url: monthURL });
|
||||
trail.push({ label: categoryLabel });
|
||||
} else {
|
||||
trail.push({ label: monthLabel });
|
||||
}
|
||||
let trail = [ { label: 'Archive' }, { label: monthLabel } ];
|
||||
return (
|
||||
<div className="page">
|
||||
<Breadcrumb trail={trail} />
|
||||
<PostList route={route} posts={posts} month={month} categories={categories} minimum={100} />
|
||||
<PostList route={route} posts={posts} minimum={100} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -67,7 +51,6 @@ if (process.env.NODE_ENV !== 'production') {
|
||||
route: PropTypes.instanceOf(Route),
|
||||
};
|
||||
ArchivePageSync.propTypes = {
|
||||
category: PropTypes.object,
|
||||
posts: PropTypes.arrayOf(PropTypes.object),
|
||||
month: PropTypes.instanceOf(Moment),
|
||||
route: PropTypes.instanceOf(Route),
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import _ from 'lodash';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { AsyncComponent } from 'relaks';
|
||||
import { Route } from 'routing';
|
||||
@@ -11,14 +12,14 @@ class CategoryPage extends AsyncComponent {
|
||||
|
||||
async renderAsync(meanwhile) {
|
||||
let { wp, route } = this.props;
|
||||
let { categorySlug } = route.params;
|
||||
let { categorySlugs } = route.params;
|
||||
let props = {
|
||||
route,
|
||||
};
|
||||
meanwhile.show(<CategoryPageSync {...props} />);
|
||||
props.categories = await wp.fetchList('/wp/v2/categories/');
|
||||
props.categories = await wp.fetchMultiple('/wp/v2/categories/', categorySlugs);
|
||||
meanwhile.show(<CategoryPageSync {...props} />);
|
||||
let category = _.find(props.categories, { slug: categorySlug });
|
||||
let category = _.last(props.categories);
|
||||
props.posts = await wp.fetchList(`/wp/v2/posts/?categories=${category.id}`);
|
||||
return <CategoryPageSync {...props} />;
|
||||
}
|
||||
@@ -29,13 +30,17 @@ class CategoryPageSync extends PureComponent {
|
||||
|
||||
render() {
|
||||
let { route, posts, categories } = this.props;
|
||||
let { categorySlug } = route.params;
|
||||
let category = _.find(categories, { slug: categorySlug });
|
||||
let categoryLabel = _.get(category, 'name', '');
|
||||
let trail = [
|
||||
{ label: 'Categories' },
|
||||
{ label: categoryLabel },
|
||||
];
|
||||
let trail = [ { label: 'Categories' } ];
|
||||
let category = _.last(categories);
|
||||
for (let c of categories) {
|
||||
let label = _.get(c, 'name', '');
|
||||
if (c !== category) {
|
||||
let url = route.getObjectURL(c);
|
||||
trail.push({ label, url });
|
||||
} else {
|
||||
trail.push({ label });
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div className="page">
|
||||
<Breadcrumb trail={trail} />
|
||||
|
@@ -14,15 +14,15 @@ class PagePage extends AsyncComponent {
|
||||
|
||||
async renderAsync(meanwhile) {
|
||||
let { wp, route } = this.props;
|
||||
let { pageSlug, parentPageSlugs } = route.params;
|
||||
let { pageSlugs } = route.params;
|
||||
let props = {
|
||||
route,
|
||||
};
|
||||
props.page = await wp.fetchOne('/wp/v2/pages/', pageSlug);
|
||||
meanwhile.show(<PagePageSync {...props} />);
|
||||
props.parentPages = await wp.fetchMultiple('/wp/v2/pages/', parentPageSlugs);
|
||||
props.pages = await wp.fetchMultiple('/wp/v2/pages/', pageSlugs);
|
||||
meanwhile.show(<PagePageSync {...props} />);
|
||||
props.childPages = await wp.fetchList(`/wp/v2/pages/?parent=${props.page.id}`, { minimum: '100%' });
|
||||
let page = _.last(props.pages);
|
||||
props.childPages = await wp.fetchList(`/wp/v2/pages/?parent=${page.id}`, { minimum: '100%' });
|
||||
return <PagePageSync {...props} />;
|
||||
}
|
||||
}
|
||||
@@ -31,25 +31,21 @@ class PagePageSync extends PureComponent {
|
||||
static displayName = 'PagePageSync';
|
||||
|
||||
render() {
|
||||
let { route, page, parentPages, childPages, transform } = this.props;
|
||||
let { route, pages, childPages, transform } = this.props;
|
||||
let page = _.last(pages);
|
||||
let trail = [];
|
||||
let parents = [];
|
||||
if (parentPages) {
|
||||
for (let parentPage of parentPages) {
|
||||
parents.push(parentPage);
|
||||
|
||||
let title = _.get(parentPage, 'title.rendered', '');
|
||||
let slugs = _.map(parents, 'slug');
|
||||
let url = route.find(slugs);
|
||||
for (let p of pages) {
|
||||
if (p !== page) {
|
||||
let title = _.get(page, 'title.rendered', '');
|
||||
let url = route.getObjectURL(p);
|
||||
trail.push({ label: <HTML text={title} />, url })
|
||||
}
|
||||
parents.push(page);
|
||||
}
|
||||
return (
|
||||
<div className="page">
|
||||
<Breadcrumb trail={trail} />
|
||||
<PageView page={page} transform={route.transformLink} />
|
||||
<PageList route={route} pages={childPages} parentPages={parents} />
|
||||
<PageList route={route} pages={childPages} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -14,20 +14,16 @@ class PostPage extends AsyncComponent {
|
||||
|
||||
async renderAsync(meanwhile) {
|
||||
let { wp, route } = this.props;
|
||||
let { monthSlug, categorySlug, postSlug } = route.params;
|
||||
let { postSlug } = route.params;
|
||||
let props = {
|
||||
route,
|
||||
};
|
||||
if (monthSlug) {
|
||||
props.month = Moment(monthSlug);
|
||||
}
|
||||
meanwhile.show(<PostPageSync {...props} />);
|
||||
if (categorySlug) {
|
||||
props.category = await wp.fetchOne('/wp/v2/categories/', categorySlug);
|
||||
meanwhile.show(<PostPageSync {...props} />);
|
||||
}
|
||||
props.post = await wp.fetchOne('/wp/v2/posts/', postSlug);
|
||||
meanwhile.show(<PostPageSync {...props} />);
|
||||
let allCategories = await wp.fetchList('/wp/v2/categories/', { minimum: '100%' });
|
||||
props.categories = findMatchingCategories(allCategories, props.post.categories, route.history);
|
||||
meanwhile.show(<PostPageSync {...props} />);
|
||||
props.author = await wp.fetchOne('/wp/v2/users/', props.post.author);
|
||||
if (!wp.ssr) {
|
||||
meanwhile.show(<PostPageSync {...props} />);
|
||||
@@ -41,36 +37,78 @@ class PostPageSync extends PureComponent {
|
||||
static displayName = 'PostPageSync';
|
||||
|
||||
render() {
|
||||
let { route, month, category, post, author, comments } = this.props;
|
||||
let { monthSlug, categorySlug } = route.params;
|
||||
let trail = [];
|
||||
if (monthSlug) {
|
||||
let monthLabel = month.format('MMMM YYYY');
|
||||
let monthURL = route.find([ monthSlug ]);
|
||||
trail.push({ label: 'Archive' });
|
||||
trail.push({ label: monthLabel, url: monthURL });
|
||||
}
|
||||
if (categorySlug) {
|
||||
let categoryLabel = _.get(category, 'name', '');
|
||||
let categoryURL;
|
||||
if (monthSlug) {
|
||||
categoryURL = route.find([ monthSlug, categorySlug ]);
|
||||
} else {
|
||||
trail.push({ label: 'Categories' });
|
||||
categoryURL = route.find([ categorySlug ]);
|
||||
}
|
||||
trail.push({ label: categoryLabel, url: categoryURL });
|
||||
let { route, categories, post, author, comments } = this.props;
|
||||
let trail = [ { label: 'Categories' } ];
|
||||
for (let c of categories) {
|
||||
let label = _.get(c, 'name', '');
|
||||
let url = route.getObjectURL(c);
|
||||
trail.push({ label, url });
|
||||
}
|
||||
return (
|
||||
<div className="page">
|
||||
<Breadcrumb trail={trail} />
|
||||
<PostView category={category} post={post} author={author} transform={route.transformLink} />
|
||||
<PostView post={post} author={author} transform={route.transformLink} />
|
||||
<CommentSection comments={comments} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function includeCategory(list, id, allCategories) {
|
||||
let category = _.find(allCategories, { id })
|
||||
if (category) {
|
||||
if (!_.includes(list, category)) {
|
||||
list.push(category);
|
||||
}
|
||||
// add parent category as well
|
||||
includeCategory(list, category.parent, allCategories);
|
||||
}
|
||||
}
|
||||
|
||||
function findMatchingCategories(allCategories, ids, history) {
|
||||
let applicable = [];
|
||||
for (let id of ids) {
|
||||
includeCategory(applicable, id, allCategories);
|
||||
}
|
||||
|
||||
let historyIndex = (c) => {
|
||||
return _.findLastIndex(history, (route) => {
|
||||
if (route.params.categorySlugs) {
|
||||
return _.includes(route.params.categorySlugs, c.slug);
|
||||
}
|
||||
});
|
||||
};
|
||||
let depth = (c) => {
|
||||
if (c.parent) {
|
||||
let parent = _.find(allCategories, { id: c.parent });
|
||||
if (parent) {
|
||||
return depth(parent) + 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
// order applicable categories based on how recently it was visited,
|
||||
// how deep it is, and alphabetically
|
||||
applicable = _.orderBy(applicable, [ historyIndex, depth, 'name' ], [ 'desc', 'desc', 'asc' ]);
|
||||
let anchorCategory = _.first(applicable);
|
||||
|
||||
let 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;
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const PropTypes = require('prop-types');
|
||||
|
||||
@@ -79,11 +117,10 @@ if (process.env.NODE_ENV !== 'production') {
|
||||
route: PropTypes.instanceOf(Route),
|
||||
};
|
||||
PostPageSync.propTypes = {
|
||||
category: PropTypes.object,
|
||||
categories: PropTypes.arrayOf(PropTypes.object),
|
||||
post: PropTypes.object,
|
||||
author: PropTypes.object,
|
||||
comments: PropTypes.arrayOf(PropTypes.object),
|
||||
month: PropTypes.instanceOf(Moment),
|
||||
route: PropTypes.instanceOf(Route),
|
||||
};
|
||||
}
|
||||
|
225
src/routing.js
225
src/routing.js
@@ -16,77 +16,113 @@ class Route {
|
||||
return this.routeManager.change(url, options);
|
||||
}
|
||||
|
||||
find(params) {
|
||||
if (params instanceof Array) {
|
||||
let slugs = params;
|
||||
return this.routeManager.find('page', { slugs });
|
||||
} else {
|
||||
return this.routeManager.find('page', params);
|
||||
}
|
||||
getRootURL() {
|
||||
return this.composeURL({ path: '/' });
|
||||
}
|
||||
|
||||
async setPageType(params) {
|
||||
let slugs = params.slugs;
|
||||
if (slugs.length > 0) {
|
||||
let slugType1 = await this.getSlugType(slugs[0]);
|
||||
if (slugType1 === 'page') {
|
||||
params.pageType = 'page';
|
||||
params.pageSlug = _.last(slugs);
|
||||
params.parentPageSlugs = _.slice(slugs, 0, -1);
|
||||
} else if (slugType1 === 'category') {
|
||||
if (slugs.length === 1) {
|
||||
params.pageType = 'category';
|
||||
params.categorySlug = slugs[0];
|
||||
} else if (slugs.length === 2) {
|
||||
params.pageType = 'post';
|
||||
params.categorySlug = slugs[0];
|
||||
params.postSlug = slugs[1];
|
||||
}
|
||||
} else if (slugType1 === 'archive') {
|
||||
if (slugs.length === 1) {
|
||||
params.pageType = 'archive';
|
||||
params.monthSlug = slugs[0];
|
||||
} else if (slugs.length === 2) {
|
||||
let slugType2 = await this.getSlugType(slugs[1]);
|
||||
if (slugType2 === 'category') {
|
||||
params.pageType = 'archive';
|
||||
params.monthSlug = slugs[0];
|
||||
params.categorySlug = slugs[1];
|
||||
} else {
|
||||
params.pageType = 'post';
|
||||
params.monthSlug = slugs[0];
|
||||
params.postSlug = slugs[1];
|
||||
}
|
||||
} else if (slugs.length === 3) {
|
||||
params.pageType = 'post';
|
||||
params.monthSlug = slugs[0];
|
||||
params.categorySlug = slugs[1];
|
||||
params.postSlug = slugs[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!params.pageType) {
|
||||
if (params.search !== undefined) {
|
||||
params.pageType = 'search';
|
||||
} else {
|
||||
params.pageType = 'welcome';
|
||||
}
|
||||
}
|
||||
getSearchURL(search) {
|
||||
return this.composeURL({ path: '/', query: { s: search } });
|
||||
}
|
||||
|
||||
async getSlugType(slug) {
|
||||
let options = { minimum: '100%' };
|
||||
let pages = await this.dataSource.fetchList('/wp/v2/pages/?parent=0', options);
|
||||
if (_.some(pages, { slug })) {
|
||||
return 'page';
|
||||
getArchiveURL(date) {
|
||||
let { year, month } = date;
|
||||
return this.composeURL({ path: `/date/${year}/${month}/` });
|
||||
}
|
||||
|
||||
getObjectURL(object) {
|
||||
let { siteURL } = this.params;
|
||||
let url = object.link;
|
||||
if (!_.startsWith(url, siteURL)) {
|
||||
throw new Error(`Object URL does not match site URL`);
|
||||
}
|
||||
let categories = await this.dataSource.fetchList('/wp/v2/categories/', options);
|
||||
if (_.some(categories, { slug })) {
|
||||
return 'category';
|
||||
let path = url.substr(siteURL.length);
|
||||
return this.composeURL({ path });
|
||||
}
|
||||
|
||||
|
||||
|
||||
composeURL(urlParts) {
|
||||
let context = _.clone(this.routeManager.context);
|
||||
this.routeManager.rewrite('to', urlParts, context);
|
||||
return this.routeManager.compose(urlParts);
|
||||
}
|
||||
|
||||
async setParameters(evt) {
|
||||
let params = await this.getParameters(evt.path, evt.query);
|
||||
params.module = require(`pages/${params.pageType}-page`);
|
||||
_.assign(evt.params, params);
|
||||
}
|
||||
|
||||
async getParameters(path, query) {
|
||||
// get the site URL and see what the page's URL would be if it
|
||||
// were on WordPress itself
|
||||
let siteURL = await this.getSiteURL();
|
||||
let link = siteURL + path;
|
||||
console.log(link);
|
||||
|
||||
// see if it's a search
|
||||
let search = query.s;
|
||||
if (search) {
|
||||
return { pageType: 'search', search, siteURL };
|
||||
}
|
||||
if (/^\d{4}\-\d{2}$/.test(slug)) {
|
||||
return 'archive';
|
||||
|
||||
// see if it's pointing to the root page
|
||||
if (path === '/') {
|
||||
return { pageType: 'welcome', siteURL };
|
||||
}
|
||||
|
||||
// see if it's pointing to an archive
|
||||
let date = findDate(path);
|
||||
if (date) {
|
||||
return { pageType: 'archive', date, siteURL };
|
||||
}
|
||||
|
||||
// see if it's pointing to a post by ID
|
||||
let postID = findPostID(path);
|
||||
if (postID) {
|
||||
let post = await this.dataSource.fetchOne('/wp/v2/posts/', postID);
|
||||
if (post) {
|
||||
let postSlug = post.slug;
|
||||
return { pageType: 'post', postSlug, siteURL };
|
||||
}
|
||||
}
|
||||
|
||||
// see if it's pointing to a page
|
||||
let allPages = await this.dataSource.fetchList('/wp/v2/pages/', { minimum: '100%' });
|
||||
let pageSlugs = findMatchingSlugs(allPages, link);
|
||||
if (pageSlugs) {
|
||||
return { pageType: 'page', pageSlugs, siteURL };
|
||||
}
|
||||
|
||||
// see if it's pointing to a category
|
||||
let allCategories = await this.dataSource.fetchList('/wp/v2/categories/', { minimum: '100%' });
|
||||
let categorySlugs = findMatchingSlugs(allCategories, link);
|
||||
if (categorySlugs) {
|
||||
return { pageType: 'category', categorySlugs, siteURL };
|
||||
}
|
||||
|
||||
// see if it's pointing to a tag
|
||||
let allTags = await this.dataSource.fetchList('/wp/v2/tags/', { minimum: '100%' });
|
||||
let tagSlugs = findMatchingSlugs(allTags, link);
|
||||
if (tagSlugs) {
|
||||
let tagSlug = tagSlugs[0];
|
||||
return { pageType: 'tag', tagSlug, siteURL };
|
||||
}
|
||||
|
||||
// see if it's pointing to a post
|
||||
let postSlug = _.last(_.filter(_.split(path, '/')));
|
||||
let post = await this.dataSource.fetchOne('/wp/v2/posts/', postSlug);
|
||||
if (post) {
|
||||
return { pageType: 'post', postSlug, siteURL };
|
||||
}
|
||||
|
||||
// go to the welcome page if we can't find a match
|
||||
return { pageType: 'welcome', siteURL };
|
||||
}
|
||||
|
||||
async getSiteURL() {
|
||||
let site = await this.dataSource.fetchOne('/');
|
||||
return _.trimEnd(site.url, '/');
|
||||
}
|
||||
|
||||
async preloadPage(params) {
|
||||
@@ -126,31 +162,44 @@ class Route {
|
||||
}
|
||||
}
|
||||
|
||||
let routes = {
|
||||
'page': {
|
||||
path: {
|
||||
from(path, params) {
|
||||
params.slugs = path.split('/').filter(Boolean);
|
||||
return true;
|
||||
},
|
||||
to(params) {
|
||||
if (params.slugs instanceof Array) {
|
||||
return `/${params.slugs.join('/')}`;
|
||||
} else {
|
||||
return `/`;
|
||||
}
|
||||
}
|
||||
},
|
||||
query: {
|
||||
search: '${search}',
|
||||
},
|
||||
load: (match) => {
|
||||
let type = match.params.pageType;
|
||||
if (type) {
|
||||
match.params.module = require(`pages/${type}-page`);
|
||||
}
|
||||
function findDate(path) {
|
||||
if (_.startsWith(path, '/date/')) {
|
||||
path = path.substr(5);
|
||||
}
|
||||
let m = /^\/(\d{4})\/(\d+)\/?/.exec(path);
|
||||
if (m) {
|
||||
return {
|
||||
year: parseInt(m[1]),
|
||||
month: parseInt(m[2]),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function findPostID(path) {
|
||||
if (_.startsWith(path, '/archives/')) {
|
||||
let id = parseInt(path.substr(10));
|
||||
if (id === id) {
|
||||
return id;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function findMatchingSlugs(objects, link) {
|
||||
let matches = [];
|
||||
for (let object of objects) {
|
||||
let objectLink = _.trimEnd(object.link, '/') + '/';
|
||||
if (_.startsWith(objectLink, link)) {
|
||||
matches.push(object);
|
||||
}
|
||||
}
|
||||
if (matches.length > 0) {
|
||||
let slugs = _.map(_.sortBy(matches, 'link.length'), 'slug');
|
||||
return slugs;
|
||||
}
|
||||
}
|
||||
|
||||
let routes = {
|
||||
'page': { path: '*' },
|
||||
};
|
||||
|
||||
export {
|
||||
|
@@ -30,6 +30,7 @@ A {
|
||||
background-color: #66023c;
|
||||
overflow: hidden;
|
||||
color: #cccccc;
|
||||
padding: 0 1em 0 1em;
|
||||
|
||||
A {
|
||||
opacity: 0.5;
|
||||
@@ -44,6 +45,10 @@ A {
|
||||
}
|
||||
}
|
||||
|
||||
UL {
|
||||
margin-left: -1em;
|
||||
}
|
||||
|
||||
.categories {
|
||||
LI {
|
||||
margin-top: 0.2em;
|
||||
|
@@ -8,11 +8,9 @@ class PageListView extends PureComponent {
|
||||
static displayName = 'PageListView';
|
||||
|
||||
render() {
|
||||
let { route, parentPages, page } = this.props;
|
||||
let { route, page } = this.props;
|
||||
let title = _.get(page, 'title.rendered', '');
|
||||
let parentSlugs = _.map(parentPages, 'slug');
|
||||
let slugs = _.concat(parentSlugs, page.slug);
|
||||
let url = route.find(slugs);
|
||||
let url = route.getObjectURL(page);
|
||||
return (
|
||||
<div className="page-list-view">
|
||||
<a href={url}><HTML text={title} /></a>
|
||||
@@ -26,7 +24,6 @@ if (process.env.NODE_ENV !== 'production') {
|
||||
|
||||
PageListView.propTypes = {
|
||||
page: PropTypes.object,
|
||||
parentPages: PropTypes.arrayOf(PropTypes.object),
|
||||
route: PropTypes.instanceOf(Route).isRequired,
|
||||
};
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ class PageList extends PureComponent {
|
||||
static displayName = 'PageList'
|
||||
|
||||
render() {
|
||||
let { route, pages, parentPages } = this.props;
|
||||
let { route, pages } = this.props;
|
||||
if (!pages) {
|
||||
return null;
|
||||
}
|
||||
@@ -18,7 +18,7 @@ class PageList extends PureComponent {
|
||||
pages.map((page) => {
|
||||
return (
|
||||
<li key={page.id}>
|
||||
<PageListView route={route} page={page} parentPages={parentPages} />
|
||||
<PageListView route={route} page={page} />
|
||||
</li>
|
||||
);
|
||||
})
|
||||
@@ -44,7 +44,6 @@ if (process.env.NODE_ENV !== 'production') {
|
||||
|
||||
PageList.propTypes = {
|
||||
pages: PropTypes.arrayOf(PropTypes.object),
|
||||
parentPages: PropTypes.arrayOf(PropTypes.object),
|
||||
route: PropTypes.instanceOf(Route).isRequired,
|
||||
};
|
||||
}
|
||||
|
@@ -9,18 +9,11 @@ class PostListView extends PureComponent {
|
||||
static displayName = 'PostListView';
|
||||
|
||||
render() {
|
||||
let { route, category, post, month } = this.props;
|
||||
let { route, post } = this.props;
|
||||
let title = _.get(post, 'title.rendered', '');
|
||||
let excerpt = _.get(post, 'excerpt.rendered', '');
|
||||
excerpt = cleanExcerpt(excerpt);
|
||||
let slugs = [ post.slug ];
|
||||
if (category) {
|
||||
slugs.unshift(category.slug);
|
||||
}
|
||||
if (month) {
|
||||
slugs.unshift(month.format('YYYY-MM'));
|
||||
}
|
||||
let url = route.find(slugs);
|
||||
let url = route.getObjectURL(post);
|
||||
return (
|
||||
<div className="post-list-view">
|
||||
<h3>
|
||||
@@ -44,9 +37,7 @@ if (process.env.NODE_ENV !== 'production') {
|
||||
const PropTypes = require('prop-types');
|
||||
|
||||
PostListView.propTypes = {
|
||||
category: PropTypes.object,
|
||||
post: PropTypes.object,
|
||||
month: PropTypes.instanceOf(Moment),
|
||||
route: PropTypes.instanceOf(Route).isRequired,
|
||||
};
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ class PostList extends PureComponent {
|
||||
static displayName = 'PostList'
|
||||
|
||||
render() {
|
||||
let { route, posts, categories, month, authors } = this.props;
|
||||
let { route, posts } = this.props;
|
||||
if (!posts) {
|
||||
return null;
|
||||
}
|
||||
@@ -17,9 +17,7 @@ class PostList extends PureComponent {
|
||||
<div className="posts">
|
||||
{
|
||||
posts.map((post) => {
|
||||
let author = _.find(authors, { id: post.author_id });
|
||||
let category = _.find(categories, { id: post.categories[0] });
|
||||
return <PostListView route={route} month={month} category={category} post={post} author={author} key={post.id} />
|
||||
return <PostListView route={route} post={post} key={post.id} />
|
||||
})
|
||||
}
|
||||
</div>
|
||||
@@ -62,8 +60,6 @@ if (process.env.NODE_ENV !== 'production') {
|
||||
const PropTypes = require('prop-types');
|
||||
|
||||
PostList.propTypes = {
|
||||
categories: PropTypes.arrayOf(PropTypes.object),
|
||||
month: PropTypes.instanceOf(Moment),
|
||||
route: PropTypes.instanceOf(Route),
|
||||
minimum: PropTypes.number,
|
||||
maximum: PropTypes.number,
|
||||
|
@@ -8,7 +8,7 @@ class PostView extends PureComponent {
|
||||
static displayName = 'PostView';
|
||||
|
||||
render() {
|
||||
let { category, post, author, transform } = this.props;
|
||||
let { post, author, transform } = this.props;
|
||||
let title = _.get(post, 'title.rendered', '');
|
||||
let content = _.get(post, 'content.rendered', '');
|
||||
let date = _.get(post, 'date_gmt');
|
||||
@@ -35,7 +35,6 @@ if (process.env.NODE_ENV !== 'production') {
|
||||
const PropTypes = require('prop-types');
|
||||
|
||||
PostView.propTypes = {
|
||||
category: PropTypes.object,
|
||||
post: PropTypes.object,
|
||||
author: PropTypes.object,
|
||||
transform: PropTypes.func,
|
||||
|
@@ -11,21 +11,13 @@ class SideNav extends AsyncComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
let { route } = this.props;
|
||||
let { monthSlug } = route.params;
|
||||
let selectedYear;
|
||||
if (monthSlug) {
|
||||
selectedYear = parseInt(monthSlug.substr(0, 4));
|
||||
} else {
|
||||
selectedYear = Moment().year();
|
||||
}
|
||||
this.state = {
|
||||
selectedYear
|
||||
};
|
||||
let { date } = route.params;
|
||||
let selectedYear = _.get(date, 'year', Moment().year());
|
||||
this.state = { selectedYear };
|
||||
}
|
||||
|
||||
async renderAsync(meanwhile) {
|
||||
let { wp, route } = this.props;
|
||||
let { monthSlug } = route.params;
|
||||
let { selectedYear } = this.state;
|
||||
let props = {
|
||||
route,
|
||||
@@ -68,7 +60,10 @@ class SideNav extends AsyncComponent {
|
||||
let monthEntry = {
|
||||
month: m + 1,
|
||||
label: start.format('MMMM'),
|
||||
slug: start.format('YYYY-MM'),
|
||||
date: {
|
||||
year: start.year(),
|
||||
month: start.month() + 1,
|
||||
},
|
||||
post: undefined,
|
||||
start,
|
||||
end,
|
||||
@@ -96,15 +91,7 @@ class SideNav extends AsyncComponent {
|
||||
// load the posts of each categories
|
||||
props.categoryPosts = [];
|
||||
for (let category of props.categories) {
|
||||
let url;
|
||||
if (monthSlug) {
|
||||
let month = Moment(monthSlug);
|
||||
let after = month.toISOString();
|
||||
let before = month.endOf('month').toISOString();
|
||||
url = `/wp/v2/posts/?after=${after}&before=${before}&categories=${category.id}`;
|
||||
} else {
|
||||
url = `/wp/v2/posts/?categories=${category.id}`;
|
||||
}
|
||||
let url = `/wp/v2/posts/?categories=${category.id}`;
|
||||
let posts = await wp.fetchList(url);
|
||||
props.categoryPosts = _.clone(props.categoryPosts);
|
||||
props.categoryPosts.push(posts);
|
||||
@@ -125,7 +112,9 @@ class SideNavSync extends PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<div className="side-nav">
|
||||
<h3>Categories</h3>
|
||||
{this.renderCategories()}
|
||||
<h3>Archives</h3>
|
||||
{this.renderArchive()}
|
||||
</div>
|
||||
)
|
||||
@@ -136,6 +125,8 @@ class SideNavSync extends PureComponent {
|
||||
if (!categories) {
|
||||
return null;
|
||||
}
|
||||
// only top-level categories
|
||||
categories = _.filter(categories, { parent: 0 });
|
||||
// don't show categories with no post
|
||||
categories = _.filter(categories, 'count');
|
||||
// list category with more posts first
|
||||
@@ -153,20 +144,16 @@ class SideNavSync extends PureComponent {
|
||||
|
||||
renderCategory(category, i) {
|
||||
let { route, categoryPosts } = this.props;
|
||||
let { monthSlug, categorySlug } = route.params;
|
||||
let { categorySlugs } = route.params;
|
||||
let name = _.get(category, 'name', '');
|
||||
let description = _.get(category, 'description', '');
|
||||
let slugs = [ category.slug ];
|
||||
if (monthSlug) {
|
||||
slugs.unshift(monthSlug);
|
||||
}
|
||||
let url = route.find(slugs);
|
||||
let url = route.getObjectURL(category);
|
||||
let posts = (categoryPosts) ? categoryPosts[i] : undefined;
|
||||
if (_.isEmpty(posts) && !_.isUndefined(posts)) {
|
||||
url = undefined;
|
||||
}
|
||||
let className;
|
||||
if (categorySlug === category.slug) {
|
||||
if (category.slug === _.last(categorySlugs)) {
|
||||
className = 'selected';
|
||||
}
|
||||
return (
|
||||
@@ -216,13 +203,13 @@ class SideNavSync extends PureComponent {
|
||||
|
||||
renderMonth(monthEntry, i) {
|
||||
let { route } = this.props;
|
||||
let { monthSlug } = route.params;
|
||||
let url = route.find([ monthEntry.slug ]);
|
||||
let { date } = route.params;
|
||||
let url = route.getArchiveURL(monthEntry.date);
|
||||
if (_.isEmpty(monthEntry.posts) && !_.isUndefined(monthEntry.posts)) {
|
||||
url = undefined;
|
||||
}
|
||||
let className;
|
||||
if (monthSlug === monthEntry.slug) {
|
||||
if (_.isEqual(monthEntry.date, date)) {
|
||||
className = 'selected';
|
||||
}
|
||||
return (
|
||||
|
@@ -46,7 +46,7 @@ class TopNavSync extends PureComponent {
|
||||
let { route, system } = this.props;
|
||||
let name = _.get(system, 'name', '');
|
||||
let description = _.get(system, 'description', '');
|
||||
let url = route.find({});
|
||||
let url = route.getRootURL();
|
||||
return (
|
||||
<div className="title-bar">
|
||||
<div className="title" title={description}>
|
||||
@@ -76,8 +76,7 @@ class TopNavSync extends PureComponent {
|
||||
renderPageLinkButton(page, i) {
|
||||
let { route } = this.props;
|
||||
let title = _.get(page, 'title.rendered');
|
||||
let slug = _.get(page, 'slug');
|
||||
let url = route.find([ slug ]);
|
||||
let url = route.getObjectURL(page);
|
||||
return (
|
||||
<div className="button" key={i}>
|
||||
<a href={url}>{title}</a>
|
||||
@@ -101,7 +100,7 @@ class TopNavSync extends PureComponent {
|
||||
performSearch = (evt) => {
|
||||
let { search } = this.state;
|
||||
let { route } = this.props;
|
||||
let url = route.find({ search });
|
||||
let url = route.getSearchURL(search);
|
||||
let options = {
|
||||
replace: (route.params.pageType === 'search')
|
||||
};
|
||||
|
Reference in New Issue
Block a user