diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 2d2b0fd..8ef9eee 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -20,7 +20,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
- dotnet-version: '6.0.x'
+ dotnet-version: '7.0.x'
- name: NuGet Restore
run: dotnet restore
- name: Build
diff --git a/Directory.Build.props b/Directory.Build.props
index 802215f..0f35cd1 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,6 +1,6 @@
- net6.0
+ net7.0
latest
enable
@@ -8,7 +8,7 @@
$(MSBuildThisFileDirectory)_artifacts
Aaron Bockover
- Copyright 2020-2021 Aaron Bockover
+ Copyright 2020-2023 Aaron Bockover
https://github.com/abock/goodbye-wordpress
MIT
diff --git a/Goodbye.WordPress.CommandLineTool/Goodbye.WordPress.CommandLineTool.csproj b/Goodbye.WordPress.CommandLineTool/Goodbye.WordPress.CommandLineTool.csproj
index cd311d5..6eece4b 100644
--- a/Goodbye.WordPress.CommandLineTool/Goodbye.WordPress.CommandLineTool.csproj
+++ b/Goodbye.WordPress.CommandLineTool/Goodbye.WordPress.CommandLineTool.csproj
@@ -10,7 +10,7 @@
$(PackageDescription)
- Note, there is a .NET 6.0 library ("Goodbye.WordPress") that
+ Note, there is a .NET 7.0 library ("Goodbye.WordPress") that
can be integrated easily into a new .NET console application that
allows heavy customization through overriding pieces of the export
pipeline in WordPressExporterDelegate.
@@ -23,5 +23,7 @@
+
+
\ No newline at end of file
diff --git a/Goodbye.WordPress.Example/JsonConfig.cs b/Goodbye.WordPress.Example/JsonConfig.cs
new file mode 100644
index 0000000..e1f5e22
--- /dev/null
+++ b/Goodbye.WordPress.Example/JsonConfig.cs
@@ -0,0 +1,74 @@
+namespace WPExportApp {
+ using System;
+ using System.Threading.Tasks;
+
+ ///
+ /// Credentials Related
+ /// Provides
+ /// - Credentials
+ /// - Additional options i.e., for SSL
+ /// - Patterns for substitution/pre-processing content
+ ///
+ class JsonConfig {
+ public WPExpJsonConfig? Options { get; set; }
+
+ ///
+ /// Config file path
+ ///
+ private string JsonConfigFilePath { get; set; }
+
+ ///
+ ///
+ /// Accessing Local App Data via Environment
+ ///
+ ///
+ public JsonConfig() {
+ JsonConfigFilePath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
+ + @"\WPExportConfig.json";
+
+ if (!System.IO.File.Exists(JsonConfigFilePath)) {
+ throw new InvalidOperationException($"Required config: {JsonConfigFilePath} not found!" +
+ "Please create the config file and run this application again.");
+ }
+ }
+
+ public class ReplacePattern {
+ public string Needle { get; set; }
+ public string Substitute { get; set; }
+ }
+
+ ///
+ /// Structure to read records from config file (json format)
+ /// Self explanatory props
+ ///
+ public class WPExpJsonConfig {
+ public string Host { get; set; }
+ public string Database { get; set; }
+ public string Username { get; set; }
+ public string Password { get; set; }
+ public string TlsVersion { get; set; }
+ public string ContentOutputDirectory { get; set; }
+ public string ArchiveOutputFilePath { get; set; }
+ ///
+ /// Some of the patterns might be internal only and should not be published online
+ /// Therefore, it might be good idea to keep them in the json config file.
+ ///
+ public ReplacePattern[] Patterns { get; set; }
+ }
+
+
+ ///
+ /// Read and Parse Config file
+ ///
+ public async Task Load() {
+ using System.IO.FileStream openStream = System.IO.File.OpenRead(JsonConfigFilePath);
+ Options = await System.Text.Json.JsonSerializer.DeserializeAsync(openStream);
+
+ if (Options == null || string.IsNullOrEmpty(Options.Host) || string.IsNullOrEmpty(
+ Options.Database) || string.IsNullOrEmpty(Options.Username) || string.IsNullOrEmpty(
+ Options.Password)) {
+ throw new NullReferenceException("Database Credentials are empty in Json config file!");
+ }
+ }
+ }
+}
diff --git a/Goodbye.WordPress.Example/Program.cs b/Goodbye.WordPress.Example/Program.cs
index 5c78484..b6d588b 100644
--- a/Goodbye.WordPress.Example/Program.cs
+++ b/Goodbye.WordPress.Example/Program.cs
@@ -1,41 +1,82 @@
-using Goodbye.WordPress;
+namespace WPExportApp {
+ using System.Threading.Tasks;
+ using Goodbye.WordPress;
-var exporter = WordPressExporter.Create(
- postReader: new MysqlPostReader(new ConnectionStringBuilder
+ class WPExportMain {
+ ///
+ /// Entry Point
+ ///
+ /// CLA
+ static async Task Main(string[] args)
+ {
+ var config = new JsonConfig();
+ await config.Load();
+ if (config.Options == null)
+ throw new System.NullReferenceException();
+
+ var exporter = WordPressExporter.Create(
+ postReader: new MysqlPostReader(
+ new ConnectionStringBuilder {
+ Host = config.Options.Host,
+ Database = config.Options.Database,
+ Username = config.Options.Username,
+ Password = config.Options.Password
+ // , TlsVersion = config.Options.TlsVersion
+ }),
+ contentOutputDirectory: config.Options.ContentOutputDirectory,
+ archiveOutputFilePath: config.Options.ArchiveOutputFilePath,
+ // And now the delegate...
+ @delegate: new CustomExporterDelegate(config.Options.Patterns)
+ );
+
+ await exporter.ExportAsync();
+ }
+ }
+
+
+ sealed class CustomExporterDelegate : WordPressExporterDelegate
{
- Host = "localhost",
- Username = "user",
- Password = "***",
- Database = "wordpressdb"
- }),
- contentOutputDirectory: "exported-posts",
- archiveOutputFilePath: "exported-posts/archive.json",
-
- // And now the delegate...
- @delegate: new CustomExporterDelegate());
-
-await exporter.ExportAsync();
-
-sealed class CustomExporterDelegate : WordPressExporterDelegate
-{
- /// Process post contents
- public override Post ProcessPost(
- WordPressExporter exporter,
- Post post)
+ JsonConfig.ReplacePattern[] StrPatterns;
+
+ public CustomExporterDelegate(JsonConfig.ReplacePattern[] patterns)
+ {
+ StrPatterns = patterns;
+ }
+
+ // Replace weird unicode chars
+ private string SubstituteCommon(string str) =>
+ str.Replace("‘", "'").Replace("’", "'")
+ .Replace("“", "\"").Replace("”", "\"");
+
+ private string ProcessContent(string content) {
+ content = SubstituteCommon(content)
+ .Replace("http://", "https://");
+
+ if (StrPatterns != null && StrPatterns.Length > 0)
+ foreach( var pattern in StrPatterns)
+ content = content.Replace(pattern.Needle, pattern.Substitute);
+
+ return content;
+ }
+
+ /// Process post contents
+ public override Post ProcessPost(
+ WordPressExporter exporter,
+ Post post)
// Perform the default post processing first by calling base
=> base.ProcessPost(exporter, post) with
{
- // Then replace '--' with Unicode em dash '—'
- Content = post.Content.Replace("--", "—")
+ Content = ProcessContent(post.Content)
};
- /// Add 'CustomMetadata' to each post's YAML front matter
- public override void PopulatePostYamlFrontMatter(
- WordPressExporter exporter,
- Post post,
- SharpYaml.Serialization.YamlMappingNode rootNode)
- {
- base.PopulatePostYamlFrontMatter(exporter, post, rootNode);
- rootNode.Add("CustomMetadata", "Some Value");
+ /// Add 'CustomMetadata' to each post's YAML front matter
+ public override void PopulatePostYamlFrontMatter(
+ WordPressExporter exporter,
+ Post post,
+ SharpYaml.Serialization.YamlMappingNode rootNode)
+ {
+ base.PopulatePostYamlFrontMatter(exporter, post, rootNode);
+ // rootNode.Add("CustomMetadata", "Some Value");
+ }
}
-}
+}
\ No newline at end of file
diff --git a/Goodbye.WordPress.Example/README.md b/Goodbye.WordPress.Example/README.md
new file mode 100644
index 0000000..8aede2f
--- /dev/null
+++ b/Goodbye.WordPress.Example/README.md
@@ -0,0 +1,24 @@
+## Example Json Config
+Default config path: "$Env:LocalAppData\WPExportConfig.json"
+
+For example, `C:\Users\UserName\AppData\Local\WPExportConfig.json`
+
+An example config looks like following,
+
+ {
+ "Host": "localhost",
+ "Username": "user",
+ "Password": "your_password",
+ "Database": "wordpress_db_name",
+ "ContentOutputDirectory": "posts",
+ "ArchiveOutputFilePath": "posts/archive.json",
+ "Patterns": [
+ {
+ "Needle": "old-domain.com",
+ "Substitute": "new-domain.com"
+ }
+ ]
+ }
+
+
+For example without json config, please have a look at [primary ReadMe](https://github.com/abock/goodbye-wordpress#example-programcs).
\ No newline at end of file
diff --git a/Goodbye.WordPress/Goodbye.WordPress.csproj b/Goodbye.WordPress/Goodbye.WordPress.csproj
index 634d916..49f17f7 100644
--- a/Goodbye.WordPress/Goodbye.WordPress.csproj
+++ b/Goodbye.WordPress/Goodbye.WordPress.csproj
@@ -10,10 +10,10 @@
-
-
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 65890a0..92fbf98 100644
--- a/README.md
+++ b/README.md
@@ -87,45 +87,86 @@ Note that with the exception of `ConnectionStringBuilder` and `WordPressExporter
Creating the exporter via API here is equivalent to the command line invocation above, with the exception of providing a custom exporter delegate that will perform additional processing steps.
```csharp
-using Goodbye.WordPress;
+namespace WPExportApp {
+ using System.Threading.Tasks;
+ using Goodbye.WordPress;
+
+ class WPExportMain {
+ ///
+ /// Entry Point
+ ///
+ /// CLA
+ static async Task Main(string[] args)
+ {
+ var config = new JsonConfig();
+ await config.Load();
+ if (config.Options == null)
+ throw new System.NullReferenceException();
+
+ var exporter = WordPressExporter.Create(
+ postReader: new MysqlPostReader(
+ new ConnectionStringBuilder {
+ Host = config.Options.Host,
+ Database = config.Options.Database,
+ Username = config.Options.Username,
+ Password = config.Options.Password
+ // , TlsVersion = config.Options.TlsVersion
+ }),
+ contentOutputDirectory: config.Options.ContentOutputDirectory,
+ archiveOutputFilePath: config.Options.ArchiveOutputFilePath,
+ // And now the delegate...
+ @delegate: new CustomExporterDelegate(config.Options.Patterns)
+ );
+
+ await exporter.ExportAsync();
+ }
+ }
-var exporter = WordPressExporter.Create(
- postReader: new MysqlPostReader(new ConnectionStringBuilder
+
+ sealed class CustomExporterDelegate : WordPressExporterDelegate
{
- Host = "localhost",
- Username = "user",
- Password = "***",
- Database = "wordpressdb"
- }),
- contentOutputDirectory: "exported-posts",
- archiveOutputFilePath: "exported-posts/archive.json",
-
- // And now the delegate...
- @delegate: new CustomExporterDelegate());
-
-await exporter.ExportAsync();
-
-sealed class CustomExporterDelegate : WordPressExporterDelegate
-{
- /// Process post contents
- public override Post ProcessPost(
- WordPressExporter exporter,
- Post post)
+ JsonConfig.ReplacePattern[] StrPatterns;
+
+ public CustomExporterDelegate(JsonConfig.ReplacePattern[] patterns)
+ {
+ StrPatterns = patterns;
+ }
+
+ // Replace weird unicode chars
+ private string SubstituteCommon(string str) =>
+ str.Replace("‘", "'").Replace("’", "'")
+ .Replace("“", "\"").Replace("”", "\"");
+
+ private string ProcessContent(string content) {
+ content = SubstituteCommon(content)
+ .Replace("http://", "https://");
+
+ if (StrPatterns != null && StrPatterns.Length > 0)
+ foreach( var pattern in StrPatterns)
+ content = content.Replace(pattern.Needle, pattern.Substitute);
+
+ return content;
+ }
+
+ /// Process post contents
+ public override Post ProcessPost(
+ WordPressExporter exporter,
+ Post post)
// Perform the default post processing first by calling base
=> base.ProcessPost(exporter, post) with
{
- // Then replace '--' with Unicode em dash '—'
- Content = post.Content.Replace("--", "—")
+ Content = ProcessContent(post.Content)
};
- /// Add 'CustomMetadata' to each post's YAML front matter
- public override void PopulatePostYamlFrontMatter(
- WordPressExporter exporter,
- Post post,
- SharpYaml.Serialization.YamlMappingNode rootNode)
- {
- base.PopulatePostYamlFrontMatter(exporter, post, rootNode);
- rootNode.Add("CustomMetadata", "Some Value");
+ /// Add 'CustomMetadata' to each post's YAML front matter
+ public override void PopulatePostYamlFrontMatter(
+ WordPressExporter exporter,
+ Post post,
+ SharpYaml.Serialization.YamlMappingNode rootNode)
+ {
+ base.PopulatePostYamlFrontMatter(exporter, post, rootNode);
+ // rootNode.Add("CustomMetadata", "Some Value");
+ }
}
}
```
\ No newline at end of file