Skip to content

feat: Add Ghost CMS integration#1324

Closed
siva-sub wants to merge 3 commits into
gitroomhq:mainfrom
siva-sub:feature/ghost-cms-integration
Closed

feat: Add Ghost CMS integration#1324
siva-sub wants to merge 3 commits into
gitroomhq:mainfrom
siva-sub:feature/ghost-cms-integration

Conversation

@siva-sub
Copy link
Copy Markdown

@siva-sub siva-sub commented Mar 17, 2026

This is an update/supersede of PR #1142 with comprehensive Ghost CMS integration fixes.

Fixes #1142 - Adds native Ghost CMS integration with scheduling, theme management, newsletters, and tiers support.

Original PR #1142 Summary

  • Ghost Admin API integration using JWT authentication (HS256)
  • Custom fields for Ghost site URL and Admin API key configuration
  • Frontend settings form with title, slug, status, feature image, tags
  • Image upload support for feature images
  • HTML editor mode for rich content

Additional Features in This PR

  • Native scheduling, update, delete via Ghost Admin API
  • Theme upload, activation, and settings management
  • Newsletters and tiers support with proper DTOs

Bug Fixes (Critical)

  • Fix Sentry issue: Added updated_at field fetching to prevent 409 UPDATE_COLLISION errors
  • The Ghost Admin API requires updated_at timestamp for optimistic concurrency control
  • Both update() and changeStatus() now fetch current post before editing to get correct updated_at
  • Fix null check in changeDate() to prevent NPE when post doesn't exist

Code Quality

  • All files have trailing newlines for lint compliance
  • Proper TypeScript types and DTOs

Testing

  • Tested with local Postiz instance and self-hosted Ghost
  • Post creation, update, and status changes work correctly
  • Image uploads verified

Supersedes: #1142

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 17, 2026

Someone is attempting to deploy a commit to the Listinai Team on Vercel.

A member of the Team first needs to authorize it.

Comment on lines +127 to +129
@IsOptional()
@IsString()
email_only?: boolean;

This comment was marked as outdated.

@siva-sub siva-sub force-pushed the feature/ghost-cms-integration branch from 0a826c8 to 5f1db3a Compare March 18, 2026 03:13
@siva-sub siva-sub force-pushed the feature/ghost-cms-integration branch from 5f1db3a to 4ddf91d Compare March 18, 2026 03:24
Comment on lines +973 to +977
try {
const updatedPost = await api.posts.edit(updateData, {
source: 'html',
include: 'tags,authors'
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The update() and changeStatus() methods are missing the required updated_at field in Ghost API calls, which will cause all post updates to fail.
Severity: CRITICAL

Suggested Fix

Before calling api.posts.edit() in both the update() and changeStatus() methods, first fetch the current post using api.posts.read({ id: ghostPostId }). Then, include the updated_at value from the fetched post in the updateData object sent to the API.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: libraries/nestjs-libraries/src/integrations/social/ghost.provider.ts#L973-L977

Potential issue: The `update()` and `changeStatus()` methods in the Ghost provider fail
to include the `updated_at` field in the payload for `api.posts.edit()` calls. The Ghost
Admin API requires this field for optimistic concurrency control to prevent write
conflicts. Its absence will cause the API to return a 409 `UPDATE_COLLISION` error for
every update attempt, effectively breaking all post editing and status change
functionality.

Ghost Admin API requires updated_at timestamp for post edits to prevent
UPDATE_COLLISION (409) errors. The fix fetches current post state before
editing to obtain the correct updated_at value.

- update() method: fetch current post, include updated_at in edit
- changeStatus() method: fetch current post, include updated_at in edit
Copy link
Copy Markdown
Author

@siva-sub siva-sub left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Fixes Applied

1. updated_at for Optimistic Concurrency (CRITICAL)

Fixed in commit ff75abe.

The update() and changeStatus() methods now fetch the current post using api.posts.read({ id: ghostPostId }) before calling api.posts.edit(), and include the updated_at timestamp from the fetched post.

// update() method - lines 974-981
const currentPost = await api.posts.read({ id: ghostPostId }, { include: 'tags,authors' });
if (!currentPost) {
  throw new Error('Post not found');
}
updateData.updated_at = currentPost.updated_at;

This satisfies Ghost Admin API's optimistic concurrency control requirement and prevents 409 UPDATE_COLLISION errors.

2. email_only validator (HIGH)

This appears to already be correct in the codebase - ghost.dto.ts line 129 shows @IsBoolean() decorator on the email_only?: boolean field. The Sentry bot comment may have been based on an outdated code snapshot.

siva-sub pushed a commit to siva-sub/postiz-agent that referenced this pull request Mar 18, 2026
- Add ghost:status - Get status of a Ghost post (draft/published/scheduled)
- Add ghost:publish - Publish a Ghost draft immediately
- Add ghost:unpublish - Convert published post back to draft
- Add ghost:schedule - Schedule a Ghost post for future publication
- Add ghost:delete - Delete a Ghost post
- Add posts:reschedule - Reschedule any post to a new date

API methods added:
- updatePostDate() - Update post schedule
- getPostStatus() - Get provider post status
- changePostStatus() - Change post status (draft/published/scheduled)
- deleteProviderPost() - Delete post from provider

Ref: gitroomhq/postiz-app#1324
- Add member_status parameter for preview (public/members/paid)
- Add include parameter for tags, authors, tiers in preview response
- Fetch and return theme CSS variables from custom_theme_settings API
- Add previewUrlWithParams for member status testing
- Implement three preview modes: static, live, member
- Add theme presets for Casper, Casper Dark, Edition, Liebling
- Add member upsell overlay simulation for member preview mode
@egelhaus egelhaus closed this Mar 18, 2026
@egelhaus egelhaus added the spam label Mar 18, 2026
siva-sub pushed a commit to siva-sub/postiz-app that referenced this pull request Mar 20, 2026
When a provider supports native scheduling (like Ghost), the Temporal
workflow now posts immediately and lets the provider handle scheduling.
This allows scheduled posts to appear in Ghost CMS immediately with
'scheduled' status instead of waiting until the publish date.

Changes:
- Add supportsNativeScheduling property to SocialAbstract base class
- Add supportsNativeScheduling to SocialProvider interface
- Set supportsNativeScheduling=true in GhostProvider
- Add supportsNativeScheduling activity to check provider capability
- Update post workflow to skip sleep for native scheduling providers

For Ghost: scheduled posts now appear in the Ghost dashboard immediately
as 'scheduled' status, and Ghost handles the actual publishing at the
configured time.

fixes gitroomhq#1324

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants