From 5172c03b7f785cc4c8bca7552abec8b0a765fd7b Mon Sep 17 00:00:00 2001 From: vitalii-bezuhlyi Date: Tue, 8 Oct 2024 10:29:58 +0300 Subject: [PATCH] Embed post and page IDs into generated HTML files and extract them in update actions --- Apps.Wordpress/Actions/PageActions.cs | 33 +++++++++++++----- Apps.Wordpress/Actions/PostActions.cs | 34 ++++++++++++++----- Apps.Wordpress/Apps.Wordpress.csproj | 7 +++- .../Requests/Page/PageOptionalRequest.cs | 12 +++++++ .../Models/Requests/Page/PageRequest.cs | 4 +-- .../Requests/Post/PostOptionalRequest.cs | 12 +++++++ README.md | 25 ++++++++++++++ 7 files changed, 106 insertions(+), 21 deletions(-) create mode 100644 Apps.Wordpress/Models/Requests/Page/PageOptionalRequest.cs create mode 100644 Apps.Wordpress/Models/Requests/Post/PostOptionalRequest.cs diff --git a/Apps.Wordpress/Actions/PageActions.cs b/Apps.Wordpress/Actions/PageActions.cs index 4af4910..5efcbc5 100644 --- a/Apps.Wordpress/Actions/PageActions.cs +++ b/Apps.Wordpress/Actions/PageActions.cs @@ -114,6 +114,10 @@ public async Task GetPageByIdAsHtml([ActionParameter] PageRequest var html = (post.Title.Rendered, post.Content.Rendered).AsHtml(); + var metaTag = $""; + var headIndex = html.IndexOf("", StringComparison.Ordinal) + "".Length; + html = html.Insert(headIndex, metaTag); + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(html)); var file = await _fileManagementClient.UploadAsync(stream, MediaTypeNames.Text.Html, $"{post.Title.Rendered}.html"); @@ -131,9 +135,12 @@ public Task CreatePage([ActionParameter] ModificationRequest inpu } [Action("Create page from HTML", Description = "Create a new page from an HTML file. With Polylang enabled it can also be used to create translations of other pages.")] - public Task CreatePageFromHtml([ActionParameter] FileModificationRequest input, [ActionParameter] PageTranslationOptions translationOptions) + public async Task CreatePageFromHtml([ActionParameter] FileModificationRequest input, [ActionParameter] PageTranslationOptions translationOptions) { - return ExecuteModification(input, translationOptions, null); + var fileStream = await _fileManagementClient.DownloadAsync(input.File); + var fileBytes = await fileStream.GetByteData(); + var html = Encoding.UTF8.GetString(fileBytes); + return await ExecuteModification(html, translationOptions, null); } [Action("Update page", Description = "Update page. With Polylang enabled it can also be used to set the language and update its associations.")] @@ -147,21 +154,29 @@ [ActionParameter] PageTranslationOptions translationOptions } [Action("Update page from HTML", Description = "Update a page from an HTML file. With Polylang enabled it can also be used to set the language and update its associations.")] - public Task UpdatePageFromHtml( - [ActionParameter] PageRequest page, + public async Task UpdatePageFromHtml( + [ActionParameter] PageOptionalRequest page, [ActionParameter] FileModificationRequest input, [ActionParameter] PageTranslationOptions translationOptions ) - { - return ExecuteModification(input, translationOptions, page.Id); - } - - private async Task ExecuteModification(FileModificationRequest input, PageTranslationOptions translationOptions, string? id) { var fileStream = await _fileManagementClient.DownloadAsync(input.File); var fileBytes = await fileStream.GetByteData(); var html = Encoding.UTF8.GetString(fileBytes); var htmlDocument = html.AsHtmlDocument(); + + var metaTag = htmlDocument.DocumentNode.SelectSingleNode("//meta[@name='blackbird-page-id']"); + var pageIdValue = metaTag?.GetAttributeValue("content", null); + + var pageId = page.Id ?? pageIdValue + ?? throw new Exception("Page ID not found in HTML file. Please make sure the file was created with the 'Get page as HTML' action, or provide the Page ID."); + + return await ExecuteModification(html, translationOptions, pageId); + } + + private async Task ExecuteModification(string html, PageTranslationOptions translationOptions, string? id) + { + var htmlDocument = html.AsHtmlDocument(); var title = htmlDocument.GetTitle(); var body = htmlDocument.GetBody(); return await ExecuteModification(new ModificationRequest { Title = title, Content = body }, translationOptions, id); diff --git a/Apps.Wordpress/Actions/PostActions.cs b/Apps.Wordpress/Actions/PostActions.cs index 6244934..ff65594 100644 --- a/Apps.Wordpress/Actions/PostActions.cs +++ b/Apps.Wordpress/Actions/PostActions.cs @@ -112,6 +112,10 @@ public async Task GetPostByIdAsHtml([ActionParameter] PostRequest var post = await Client.ExecuteWithHandling(request); var html = (post.Title.Rendered, post.Content.Rendered).AsHtml(); + + var metaTag = $""; + var headIndex = html.IndexOf("", StringComparison.Ordinal) + "".Length; + html = html.Insert(headIndex, metaTag); using var stream = new MemoryStream(Encoding.UTF8.GetBytes(html)); var file = await _fileManagementClient.UploadAsync(stream, MediaTypeNames.Text.Html, @@ -130,9 +134,13 @@ public Task CreatePost([ActionParameter] ModificationRequest inpu } [Action("Create post from HTML", Description = "Create a new post from an HTML file. With Polylang enabled it can also be used to create translations of other posts.")] - public Task CreatePostFromHtml([ActionParameter] FileModificationRequest input, [ActionParameter] PostTranslationOptions translationOptions) + public async Task CreatePostFromHtml([ActionParameter] FileModificationRequest input, [ActionParameter] PostTranslationOptions translationOptions) { - return ExecuteModification(input, translationOptions, null); + var fileStream = await _fileManagementClient.DownloadAsync(input.File); + var fileBytes = await fileStream.GetByteData(); + var html = Encoding.UTF8.GetString(fileBytes); + + return await ExecuteModification(html, translationOptions, null); } [Action("Update post", Description = "Update post. With Polylang enabled it can also be used to set the language and update its associations.")] @@ -146,21 +154,29 @@ [ActionParameter] PostTranslationOptions translationOptions } [Action("Update post from HTML", Description = "Update a post from an HTML file. With Polylang enabled it can also be used to set the language and update its associations.")] - public Task UpdatePostFromHtml( - [ActionParameter] PostRequest post, + public async Task UpdatePostFromHtml( + [ActionParameter] PostOptionalRequest post, [ActionParameter] FileModificationRequest input, [ActionParameter] PostTranslationOptions translationOptions ) - { - return ExecuteModification(input, translationOptions, post.Id); - } - - private async Task ExecuteModification(FileModificationRequest input, PostTranslationOptions translationOptions, string? id) { var fileStream = await _fileManagementClient.DownloadAsync(input.File); var fileBytes = await fileStream.GetByteData(); var html = Encoding.UTF8.GetString(fileBytes); var htmlDocument = html.AsHtmlDocument(); + + var metaTag = htmlDocument.DocumentNode.SelectSingleNode("//meta[@name='blackbird-post-id']"); + var postIdValue = metaTag?.GetAttributeValue("content", null); + + var postId = post.Id ?? postIdValue + ?? throw new Exception("Post ID not found in HTML file. Please make sure the file was created with the 'Get post as HTML' action. Or add optional Post ID parameter."); + + return await ExecuteModification(html, translationOptions, postId); + } + + private async Task ExecuteModification(string html, PostTranslationOptions translationOptions, string? id) + { + var htmlDocument = html.AsHtmlDocument(); var title = htmlDocument.GetTitle(); var body = htmlDocument.GetBody(); return await ExecuteModification(new ModificationRequest { Title = title, Content = body }, translationOptions, id); diff --git a/Apps.Wordpress/Apps.Wordpress.csproj b/Apps.Wordpress/Apps.Wordpress.csproj index ddc91a7..1eacf48 100644 --- a/Apps.Wordpress/Apps.Wordpress.csproj +++ b/Apps.Wordpress/Apps.Wordpress.csproj @@ -4,7 +4,7 @@ enable enable Wordpress (+ Polylang) - 1.2.3 + 1.2.4 The world’s most popular website builder Apps.Wordpress @@ -18,4 +18,9 @@ + + + README.md + + \ No newline at end of file diff --git a/Apps.Wordpress/Models/Requests/Page/PageOptionalRequest.cs b/Apps.Wordpress/Models/Requests/Page/PageOptionalRequest.cs new file mode 100644 index 0000000..b0f2900 --- /dev/null +++ b/Apps.Wordpress/Models/Requests/Page/PageOptionalRequest.cs @@ -0,0 +1,12 @@ +using Apps.Wordpress.DataSourceHandlers; +using Blackbird.Applications.Sdk.Common; +using Blackbird.Applications.Sdk.Common.Dynamic; + +namespace Apps.Wordpress.Models.Requests.Page; + +public class PageOptionalRequest +{ + [Display("Page ID")] + [DataSource(typeof(PageDataHandler))] + public string? Id { get; set; } +} \ No newline at end of file diff --git a/Apps.Wordpress/Models/Requests/Page/PageRequest.cs b/Apps.Wordpress/Models/Requests/Page/PageRequest.cs index 67f41ec..b563fc8 100644 --- a/Apps.Wordpress/Models/Requests/Page/PageRequest.cs +++ b/Apps.Wordpress/Models/Requests/Page/PageRequest.cs @@ -6,7 +6,7 @@ namespace Apps.Wordpress.Models.Requests.Page; public class PageRequest { - [Display("Page")] + [Display("Page ID")] [DataSource(typeof(PageDataHandler))] - public string Id { get; set; } + public string Id { get; set; } = string.Empty; } \ No newline at end of file diff --git a/Apps.Wordpress/Models/Requests/Post/PostOptionalRequest.cs b/Apps.Wordpress/Models/Requests/Post/PostOptionalRequest.cs new file mode 100644 index 0000000..7e8dc6e --- /dev/null +++ b/Apps.Wordpress/Models/Requests/Post/PostOptionalRequest.cs @@ -0,0 +1,12 @@ +using Apps.Wordpress.DataSourceHandlers; +using Blackbird.Applications.Sdk.Common; +using Blackbird.Applications.Sdk.Common.Dynamic; + +namespace Apps.Wordpress.Models.Requests.Post; + +public class PostOptionalRequest +{ + [Display("Post ID")] + [DataSource(typeof(PostDataHandler))] + public string? Id { get; set; } +} \ No newline at end of file diff --git a/README.md b/README.md index 3c078ae..322c6bc 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,31 @@ All create and update actions optionally take a language and "as translation of" - **Get languages (P)** returns all languages configured and their additional information. Polylang required. +### HTML features + +We add metadata to the HTML file to include `Post ID` and `Page ID`. This metadata is used to update the correct post or page. The metadata is added as a `meta` tag in the `head` of the HTML file. The `name` attribute is `blackbird-post-id` or `blackbird-page-id` and the `content` attribute is the ID of the post or page. + +```html + + + + Sample Page + + +

This is an example page. It’s different from a blog post because it will stay in one place and will show up in your site navigation (in most themes). Most people start with an About page that introduces them to potential site visitors. It might say something like this:

+
+

Hi there! I’m a bike messenger by day, aspiring actor by night, and this is my website. I live in Los Angeles, have a great dog named Jack, and I like piña coladas. (And gettin’ caught in the rain.)

+
+

…or something like this:

+
+

The XYZ Doohickey Company was founded in 1971, and has been providing quality doohickeys to the public ever since. Located in Gotham City, XYZ employs over 2,000 people and does all kinds of awesome things for the Gotham community.

+
+

As a new WordPress user, you should go to your dashboard to delete this page and create new pages for your content. Have fun!

+ + +``` + +Example of how we include metadata in the HTML file: ### Missing features In the future we will add actions for: