Skip to content

Commit 0059752

Browse files
committed
feat: move the file writes to loadContent to work with @docusaurus/plugin-content-blog
check the modification time of local files, to prevent overwritting any local changes
1 parent 9b008bd commit 0059752

3 files changed

Lines changed: 110 additions & 45 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "wordpress-to-docusaurus-plugin",
3-
"version": "0.0.3",
3+
"version": "1.0.0",
44
"description": "Docusaurus plugin for importing Wordpress posts",
55
"main": "dist/index.js",
66
"repository": "https://github.com/mark-tate/wordpress-to-docusaurus-plugin",

src/index.ts

Lines changed: 99 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
import path from "path";
2-
const fs = require("fs").promises;
2+
const existsSync = require("fs").existsSync;
3+
const fsPromises = require("fs").promises;
4+
const statSync = require("fs").statSync;
5+
const utimesSync = require("fs").utimesSync;
36

47
import { request as graphQLRequest } from "graphql-request";
5-
import { LoadedContent, PluginOptions, Post } from "./types";
6-
import { LoadContext, PluginContentLoadedActions } from "@docusaurus/types";
8+
import {
9+
CreateFrontmatterCallback,
10+
CreatePreviewCallback,
11+
LoadContent,
12+
PluginOptions,
13+
Post,
14+
TranslateContentCallback,
15+
} from "./types";
16+
import { LoadContext } from "@docusaurus/types";
717

818
const defaultQuery = `
919
query {
@@ -20,7 +30,8 @@ const defaultQuery = `
2030
sourceUrl
2131
}
2232
}
23-
content
33+
content,
34+
modifiedGmt
2435
}
2536
}
2637
}
@@ -35,16 +46,18 @@ export function defaultTranslateContent(content: string): string {
3546
// move lists to a new line
3647
.replace(/<\/li>/g, "</li> \n")
3748
// code-blocks to markdown code block
38-
.replace(/<pre class="wp-block-code"><code>/g, "\n```\n")
49+
.replace(/<pre [^>]*class="wp-block-code"[^>]*><code [^>]*>/g, "\n```\n")
3950
.replace(/<\/code><\/pre>/g, "\n```\n")
4051
// remove WP width and height from images
4152
.replace(
4253
/(<img[^\>]*) height="[^\"]*"(.*)/g,
4354
(_match: string, match1: string, match2: string) => `${match1}${match2}`
4455
)
4556
// paragraphs to markdown paragraphs
46-
.replace(/<p>/g, "")
47-
.replace(/<\/p>/g, " `\n")
57+
.replace(/<p[^>]*>/g, "")
58+
.replace(/<\/p>/g, " \n")
59+
.replace(/style="[^"]*"/g, "")
60+
.replace(/class="/g, 'className="')
4861
);
4962
}
5063

@@ -78,6 +91,42 @@ function formatBlogDate(date: Date): string {
7891
);
7992
}
8093

94+
const writePost = (
95+
post: Post,
96+
outputPath: string,
97+
{
98+
createFrontmatter,
99+
createPreview,
100+
translateContent,
101+
}: {
102+
createFrontmatter: CreateFrontmatterCallback;
103+
createPreview: CreatePreviewCallback;
104+
translateContent: TranslateContentCallback;
105+
}
106+
) => {
107+
const { content, modifiedGmt } = post.node;
108+
const blogModifiedDate = new Date(modifiedGmt);
109+
const blogDoc = [
110+
"---",
111+
createFrontmatter(post),
112+
"---",
113+
createPreview(post),
114+
"",
115+
"<!--truncate-->",
116+
translateContent(content, post),
117+
].join("\n");
118+
return fsPromises
119+
.writeFile(outputPath, blogDoc)
120+
.then(() => {
121+
utimesSync(outputPath, blogModifiedDate, blogModifiedDate);
122+
console.log(`Saved ${outputPath}`);
123+
return content;
124+
})
125+
.catch((err: Error) => {
126+
console.error(`Error Saving ${outputPath} - ${err}`);
127+
});
128+
};
129+
81130
export default function pluginWordpressToDocusaurus(
82131
context: LoadContext,
83132
options: PluginOptions
@@ -96,41 +145,51 @@ export default function pluginWordpressToDocusaurus(
96145
getClientModules() {
97146
return theme;
98147
},
99-
async loadContent(): Promise<LoadedContent> {
100-
const response = await graphQLRequest(url, query);
101-
return response;
102-
},
103-
async contentLoaded({
104-
content,
105-
}: {
106-
readonly content: LoadedContent;
107-
readonly actions: PluginContentLoadedActions;
108-
}): Promise<string[]> {
148+
async loadContent(): Promise<LoadContent[]> {
149+
const content = await graphQLRequest(url, query);
109150
const { posts: { edges = [] } = {} } = content;
110-
const postPromises = edges.map(async (post: Post) => {
111-
const { content, date: dateStr, slug } = post.node;
112-
const blogDate = new Date(dateStr);
113-
const blogFile = `${formatBlogDate(blogDate)}-${slug}.mdx`;
114-
const blogPath = path.resolve(context.siteDir, outputPath, blogFile);
115-
const blogDoc = [
116-
"---",
117-
createFrontmatter(post),
118-
"---",
119-
createPreview(post),
120-
"",
121-
"<!--truncate-->",
122-
translateContent(content, post),
123-
].join("\n");
124-
return fs
125-
.writeFile(blogPath, blogDoc)
126-
.then(() => {
127-
console.log(`Saved ${blogPath}`);
128-
})
129-
.catch((err: Error) => {
130-
console.error(`Error Saving ${blogPath} - ${err}`);
151+
const postPromises: Array<Promise<LoadContent>> = edges.reduce(
152+
(results: Array<Promise<LoadContent>>, post: Post) => {
153+
const { date: dateStr, slug, modifiedGmt } = post.node;
154+
const blogDate = new Date(dateStr);
155+
const blogFile = `${formatBlogDate(blogDate)}-${slug}.mdx`;
156+
const blogOutputPath = path.resolve(
157+
context.siteDir,
158+
outputPath,
159+
blogFile
160+
);
161+
const blogModifiedDate = new Date(modifiedGmt);
162+
const isExistingPost = existsSync(blogOutputPath);
163+
if (isExistingPost) {
164+
const localFile = statSync(blogOutputPath);
165+
const localModifiedGmt = new Date(localFile.mtime);
166+
if (
167+
blogModifiedDate.toISOString() === localModifiedGmt.toISOString()
168+
) {
169+
console.warn(
170+
`The remote version of ${blogOutputPath} has not changed`
171+
);
172+
return [...results, Promise.resolve(content)];
173+
} else if (localModifiedGmt > blogModifiedDate) {
174+
console.warn(
175+
[
176+
`The local version of ${blogOutputPath} has been modified, so will not be updated.`,
177+
"Remove the local file/change to restore to the remote version",
178+
].join("\n")
179+
);
180+
return [...results, Promise.resolve(content)];
181+
}
182+
}
183+
const writeBlogPromise = writePost(post, blogOutputPath, {
184+
createFrontmatter,
185+
createPreview,
186+
translateContent,
131187
});
132-
});
133-
return await Promise.all(postPromises);
188+
return [...results, writeBlogPromise];
189+
},
190+
[]
191+
);
192+
return Promise.all(postPromises);
134193
},
135194
};
136195
}

src/types.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,36 @@ export interface Post {
1515
excerpt: string;
1616
/** Featured image */
1717
featuredImage?: Image;
18+
/** Last modified date of post */
19+
modifiedGmt: string;
1820
/** Post id */
1921
slug: string;
2022
/** Post title description */
2123
title: string;
2224
};
2325
}
2426

25-
export interface LoadedContent {
27+
export interface LoadContent {
2628
posts: {
2729
readonly edges: ReadonlyArray<Post>;
2830
};
2931
}
3032

33+
export type CreateFrontmatterCallback = (post: Post) => string;
34+
export type CreatePreviewCallback = (post: Post) => string;
35+
export type TranslateContentCallback = (content: string, post: Post) => string;
36+
3137
export interface PluginOptions {
3238
/** Create Frontmatter function */
33-
createFrontmatter?: (post: Post) => string;
39+
createFrontmatter?: CreateFrontmatterCallback;
3440
/** Create Preview function */
35-
createPreview?: (post: Post) => string;
41+
createPreview?: CreatePreviewCallback;
3642
/** Output sub-directory, below site dir (default blog) */
3743
outputPath?: string;
3844
/** GraphQL query */
3945
query?: string;
4046
/** Translate content function */
41-
translateContent?: (content: string, post: Post) => string;
47+
translateContent?: TranslateContentCallback;
4248
/** URL of the Wordpress GraphQL endpoint **/
4349
url: string;
4450
/** Array of css files to load */

0 commit comments

Comments
 (0)